From 88c9516e20bbfd1f5fb9ec478cc9a1624f6eed33 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Mon, 2 May 2016 10:50:23 -0700 Subject: [PATCH] Getting started on translations (#423) --- .gitignore | 1 - CONTRIBUTING.md | 44 ++++++- babel/babel.cfg | 4 + babel/messages.pot | 117 +++++++++++++++++ caravel/assets/stylesheets/caravel.css | 4 + caravel/config.py | 4 +- caravel/models.py | 12 +- .../templates/appbuilder/navbar_right.html | 6 +- caravel/templates/caravel/basic.html | 1 + caravel/templates/caravel/welcome.html | 4 +- .../translations/es/LC_MESSAGES/messages.po | 118 ++++++++++++++++++ .../translations/fr/LC_MESSAGES/messages.mo | Bin 0 -> 2361 bytes .../translations/fr/LC_MESSAGES/messages.po | 118 ++++++++++++++++++ .../translations/zh/LC_MESSAGES/messages.mo | Bin 0 -> 2352 bytes .../translations/zh/LC_MESSAGES/messages.po | 118 ++++++++++++++++++ caravel/views.py | 39 +++--- pypi_push.sh | 6 + setup.py | 2 + 18 files changed, 566 insertions(+), 32 deletions(-) create mode 100644 babel/babel.cfg create mode 100644 babel/messages.pot create mode 100644 caravel/translations/es/LC_MESSAGES/messages.po create mode 100644 caravel/translations/fr/LC_MESSAGES/messages.mo create mode 100644 caravel/translations/fr/LC_MESSAGES/messages.po create mode 100644 caravel/translations/zh/LC_MESSAGES/messages.mo create mode 100644 caravel/translations/zh/LC_MESSAGES/messages.po create mode 100644 pypi_push.sh diff --git a/.gitignore b/.gitignore index 31859aa8fa22..4c93a874bad0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.pyc changelog.sh -babel .DS_Store .coverage _build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8f25e9ee389..ed9ff1e97e74 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -159,12 +159,12 @@ Generate the documentation with: cd docs && ./build.sh ## CSS Themes -As part of the npm build process, CSS for Caravel is compiled from ```Less```, a dynamic stylesheet language. +As part of the npm build process, CSS for Caravel is compiled from `Less`, a dynamic stylesheet language. It's possible to customize or add your own theme to Caravel, either by overriding CSS rules or preferably -by modifying the Less variables or files in ```assets/stylesheets/less/```. +by modifying the Less variables or files in `assets/stylesheets/less/`. -The ```variables.less``` and ```bootswatch.less``` files that ship with Caravel are derived from +The `variables.less` and `bootswatch.less` files that ship with Caravel are derived from [Bootswatch](https://bootswatch.com) and thus extend Bootstrap. Modify variables in these files directly, or swap them out entirely with the equivalent files from other Bootswatch (themes)[https://github.com/thomaspark/bootswatch.git] @@ -179,7 +179,43 @@ meets these guidelines: as part of the same PR. Doc string are often sufficient, make sure to follow the sphinx compatible standards. 3. The pull request should work for Python 2.6, 2.7, and ideally python 3.3. - `from __future__ import ` will be required in every `.py` file soon. + ``from __future__ import`` will be required in every `.py` file soon. 4. Code will be reviewed by re running the unittests, flake8 and syntax should be as rigorous as the core Python project. 5. Please rebase and resolve all conflicts before submitting. + + +## Tranlations + +We use [Babel](http://babel.pocoo.org/en/latest/) to translate Caravel. The +key is to instrument the strings that need translation using +`from flask.ext.babelpkg import lazy_gettext as _`. Once this is imported in +a module, all you have to do is to `_("Wrap your strings")` using the +underscore `_` "function". + +To enable changing language in your environment, you can simply add the +`LANGUAGES` parameter to your `caravel_config.py`. Having more than one +options here will add a language selection dropdown on the right side of the +navigation bar. + + LANGUAGES = { + 'en': {'flag': 'us', 'name': 'English'}, + 'fr': {'flag': 'fr', 'name': 'French'}, + 'zh': {'flag': 'cn', 'name': 'Chinese'}, + } + +As per the [Flask AppBuilder documentation] about translation, to create a +new language dictionary, run the following command: + + pybabel init -i ./babel/messages.pot -d caravel/translations -l es + +Then it's a matter of running the statement bellow to gather all stings that +need translation + + fabmanager babel-extract --target caravel/translations/ + +You can then translate the strings gathered in files located under +`caravel/translation`, where there's one per language. For the translations +to take effect, they need to be compiled using this command: + + fabmanager babel-compile --target caravel/translations/ diff --git a/babel/babel.cfg b/babel/babel.cfg new file mode 100644 index 000000000000..9daea0201c67 --- /dev/null +++ b/babel/babel.cfg @@ -0,0 +1,4 @@ +[ignore: caravel/assets/node_modules/**] +[python: caravel/**.py] +[jinja2: caravel/**/templates/**.html] +encoding = utf-8 diff --git a/babel/messages.pot b/babel/messages.pot new file mode 100644 index 000000000000..66280dee0a4c --- /dev/null +++ b/babel/messages.pot @@ -0,0 +1,117 @@ +# Translations template for Caravel. +# Copyright (C) 2016 ORGANIZATION +# This file is distributed under the same license as the Caravel project. +# Maxime Beauchemin , 2016. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2016-05-02 00:21-0700\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.3.4\n" + +#: caravel/models.py:564 +msgid "" +"Datetime column not provided as part table configuration and is required " +"by this type of chart" +msgstr "" + +#: caravel/models.py:1153 +msgid "No data was returned." +msgstr "" + +#: caravel/views.py:116 +msgid "" +"Whether to make this column available as a [Time Granularity] option, " +"column has to be DATETIME or DATETIME-like" +msgstr "" + +#: caravel/views.py:215 +msgid "Databases" +msgstr "" + +#: caravel/views.py:217 caravel/views.py:261 caravel/views.py:284 +msgid "Sources" +msgstr "" + +#: caravel/views.py:260 +msgid "Tables" +msgstr "" + +#: caravel/views.py:282 +msgid "Druid Clusters" +msgstr "" + +#: caravel/views.py:313 +msgid "Slices" +msgstr "" + +#: caravel/views.py:341 +msgid "" +"This json object describes the positioning of the widgets in the " +"dashboard. It is dynamically generated when adjusting the widgets size " +"and positions by using drag & drop in the dashboard view" +msgstr "" + +#: caravel/views.py:346 +msgid "" +"The css for individual dashboards can be altered here, or in the " +"dashboard view where changes are immediately visible" +msgstr "" + +#: caravel/views.py:367 +msgid "Dashboards" +msgstr "" + +#: caravel/views.py:392 +msgid "Action Log" +msgstr "" + +#: caravel/views.py:393 +msgid "Security" +msgstr "" + +#: caravel/views.py:430 +msgid "Druid Datasources" +msgstr "" + +#: caravel/views.py:514 +msgid "The datasource seems to have been deleted" +msgstr "" + +#: caravel/views.py:522 +msgid "You don't seem to have access to this datasource" +msgstr "" + +#: caravel/views.py:843 +msgid "This view requires the `all_datasource_access` permission" +msgstr "" + +#: caravel/views.py:954 +msgid "CSS Templates" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:34 +msgid "Profile" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:35 +msgid "Logout" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:40 +msgid "Login" +msgstr "" + +#: caravel/templates/caravel/welcome.html:8 +#: caravel/templates/caravel/welcome.html:13 +msgid "Welcome!" +msgstr "" + diff --git a/caravel/assets/stylesheets/caravel.css b/caravel/assets/stylesheets/caravel.css index e12ebb061097..05614ecd6365 100644 --- a/caravel/assets/stylesheets/caravel.css +++ b/caravel/assets/stylesheets/caravel.css @@ -2,6 +2,10 @@ body { margin: 0px !important; } +.caret { + border-top: 4px solid; +} + .emph { font-weight: bold; } diff --git a/caravel/config.py b/caravel/config.py index 07df0b5bf9c7..2c43513a76c1 100644 --- a/caravel/config.py +++ b/caravel/config.py @@ -99,10 +99,12 @@ # Setup default language BABEL_DEFAULT_LOCALE = 'en' # Your application default translation path -BABEL_DEFAULT_FOLDER = 'translations' +BABEL_DEFAULT_FOLDER = 'babel/translations' # The allowed translation for you app LANGUAGES = { 'en': {'flag': 'us', 'name': 'English'}, + # 'fr': {'flag': 'fr', 'name': 'French'}, + # 'zh': {'flag': 'cn', 'name': 'Chinese'}, } # --------------------------------------------------- # Image and file configuration diff --git a/caravel/models.py b/caravel/models.py index 30494d6f7df4..4abc2a01426e 100644 --- a/caravel/models.py +++ b/caravel/models.py @@ -18,11 +18,14 @@ import sqlalchemy as sqla import sqlparse from dateutil.parser import parse + from flask import request, g from flask.ext.appbuilder import Model from flask.ext.appbuilder.models.mixins import AuditMixin -from pydruid.client import PyDruid from flask.ext.appbuilder.models.decorators import renders +from flask.ext.babelpkg import lazy_gettext as _ + +from pydruid.client import PyDruid from pydruid.utils.filters import Dimension, Filter from pydruid.utils.postaggregator import Postaggregator from six import string_types @@ -33,7 +36,6 @@ from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.orm import relationship from sqlalchemy.sql import table, literal_column, text, column -from sqlalchemy.sql.elements import ColumnClause from sqlalchemy_utils import EncryptedType from caravel import app, db, get_session, utils @@ -571,9 +573,9 @@ def query( # sqla qry_start_dttm = datetime.now() if not granularity and is_timeseries: - raise Exception( + raise Exception(_( "Datetime column not provided as part table configuration " - "and is required by this type of chart") + "and is required by this type of chart")) metrics_exprs = [ m.sqla_col @@ -1191,7 +1193,7 @@ def query( # druid query_str += json.dumps(client.query_dict, indent=2) df = client.export_pandas() if df is None or df.size == 0: - raise Exception("No data was returned.") + raise Exception(_("No data was returned.")) if ( not is_timeseries and diff --git a/caravel/templates/appbuilder/navbar_right.html b/caravel/templates/appbuilder/navbar_right.html index 433bf1bf48db..5b1ecd560d9c 100644 --- a/caravel/templates/appbuilder/navbar_right.html +++ b/caravel/templates/appbuilder/navbar_right.html @@ -1,15 +1,14 @@ -{% macro locale_menu(languages) %} {% set locale = session['locale'] %} {% if not locale %} {% set locale = 'en' %} {% endif %} +{% if languages.keys()|length > 1 %} -{% endmacro %} +{% endif %} diff --git a/caravel/templates/caravel/basic.html b/caravel/templates/caravel/basic.html index eb62dc21560a..72b8485cb5f4 100644 --- a/caravel/templates/caravel/basic.html +++ b/caravel/templates/caravel/basic.html @@ -9,6 +9,7 @@ {% block head_css %} + {% endblock %} {% block head_js %} diff --git a/caravel/templates/caravel/welcome.html b/caravel/templates/caravel/welcome.html index 4d614a2c00fa..492876268dda 100644 --- a/caravel/templates/caravel/welcome.html +++ b/caravel/templates/caravel/welcome.html @@ -5,12 +5,12 @@ {% endblock %} -{% block title %}Welcome!{% endblock %} +{% block title %}{{ _("Welcome!") }}{% endblock %} {% block body %}
-

Welcome!

+

{{ _("Welcome!") }}


diff --git a/caravel/translations/es/LC_MESSAGES/messages.po b/caravel/translations/es/LC_MESSAGES/messages.po new file mode 100644 index 000000000000..60ee1034f49f --- /dev/null +++ b/caravel/translations/es/LC_MESSAGES/messages.po @@ -0,0 +1,118 @@ +# Spanish translations for PROJECT. +# Copyright (C) 2016 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2016-05-02 00:21-0700\n" +"PO-Revision-Date: 2016-05-02 08:49-0700\n" +"Last-Translator: FULL NAME \n" +"Language: es\n" +"Language-Team: es \n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.3.4\n" + +#: caravel/models.py:564 +msgid "" +"Datetime column not provided as part table configuration and is required " +"by this type of chart" +msgstr "" + +#: caravel/models.py:1153 +msgid "No data was returned." +msgstr "" + +#: caravel/views.py:116 +msgid "" +"Whether to make this column available as a [Time Granularity] option, " +"column has to be DATETIME or DATETIME-like" +msgstr "" + +#: caravel/views.py:215 +msgid "Databases" +msgstr "" + +#: caravel/views.py:217 caravel/views.py:261 caravel/views.py:284 +msgid "Sources" +msgstr "" + +#: caravel/views.py:260 +msgid "Tables" +msgstr "" + +#: caravel/views.py:282 +msgid "Druid Clusters" +msgstr "" + +#: caravel/views.py:313 +msgid "Slices" +msgstr "" + +#: caravel/views.py:341 +msgid "" +"This json object describes the positioning of the widgets in the " +"dashboard. It is dynamically generated when adjusting the widgets size " +"and positions by using drag & drop in the dashboard view" +msgstr "" + +#: caravel/views.py:346 +msgid "" +"The css for individual dashboards can be altered here, or in the " +"dashboard view where changes are immediately visible" +msgstr "" + +#: caravel/views.py:367 +msgid "Dashboards" +msgstr "" + +#: caravel/views.py:392 +msgid "Action Log" +msgstr "" + +#: caravel/views.py:393 +msgid "Security" +msgstr "" + +#: caravel/views.py:430 +msgid "Druid Datasources" +msgstr "" + +#: caravel/views.py:514 +msgid "The datasource seems to have been deleted" +msgstr "" + +#: caravel/views.py:522 +msgid "You don't seem to have access to this datasource" +msgstr "" + +#: caravel/views.py:843 +msgid "This view requires the `all_datasource_access` permission" +msgstr "" + +#: caravel/views.py:954 +msgid "CSS Templates" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:34 +msgid "Profile" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:35 +msgid "Logout" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:40 +msgid "Login" +msgstr "" + +#: caravel/templates/caravel/welcome.html:8 +#: caravel/templates/caravel/welcome.html:13 +msgid "Welcome!" +msgstr "" + diff --git a/caravel/translations/fr/LC_MESSAGES/messages.mo b/caravel/translations/fr/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..af915a1f58eab84089614ca3b1fc777166e8b497 GIT binary patch literal 2361 zcmeH{&u<$=6vwwvAo#!m35f$j4cc0gj?#`H* z*`(&mk#gXG`X5w6;>M9nCAe_pj8s)f96($+bK(2ePSe6)5D9C&pLw%y=6&CLv-|Mn zlV3;py@LO1`2Q%z6Tjj_6g6O%bKU`8g#9`A3HT-W68Iru!3y&o@HF^6_yGJ3d=I?;>}>rba02^xFabY28AW#y^9xXPzKYF- zZ-Sz;35w2TP;}k{Mdy7GSM)7zlKXd{===$kbw7i+qF?6ozs~JHK+*XZC^~a2dH{X} ziq0OAl=yc+(RmLPoeQ$*S{k%9)U|okR(?FR%4HtIpoYqGJ>sBCrqmWyX~@_>6KD5z z#u+J36XgQIxeyOC(s|`ny`wT2X-|$nt+a#ha7tl}i7=fo*%75O(iv?Ol@IKE z1R2`M-Buymwv<5!9UzS3P&va{Gum}_qzjJvoK{YUY1A)t3ZZ>lIpILG0AmR9o<`P@ zHkpRtN)_1fFh@$2p&^qh5E=T$xSyfg8$$WWllCOf~X2ajx?*4L!XAeGLhMwL2M1@z=>7=1um&}~R%dnmB%_2foge}?qYro&)fnpAo5 z%bd#T6ksR+30N0omOx#ad5dSlZz2B8qY~UyDVpMM(S%*8y+=yXbuLm{@*C0hF+-1& z0+s4ELmbkWpEI?ubWtBGbYIa&1380NoibISr0pM*ok)Ss94;8c4;!JQ?X^K?u({Qd zW*&~?Lf_`-hOH>G=B-e7=5b?Y8pW&?9I2PXCe4XAv-ld$C*rkex3}|tXJbIuI=%kp z&UT~66YD~}<#V0I>s9XKfo)M|Yi+Z8d9B^|Ia9qC`aT|?k(NeN_K2F|^ zlO;-$RnmC6xvh-n@MBCn!pB{@Orl>@SSjWQYdXM)-Sr}uu_FlynN&*+DGi-j!A8XBiEwk vp$?6!hbK2)pSEaS4Y{DD=DFrOjbs0*`r(`Zzg5TWTeYs)?6awk#n, 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2016-05-02 00:21-0700\n" +"PO-Revision-Date: 2016-05-01 23:07-0700\n" +"Last-Translator: FULL NAME \n" +"Language: fr\n" +"Language-Team: fr \n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.3.4\n" + +#: caravel/models.py:564 +msgid "" +"Datetime column not provided as part table configuration and is required " +"by this type of chart" +msgstr "" + +#: caravel/models.py:1153 +msgid "No data was returned." +msgstr "" + +#: caravel/views.py:116 +msgid "" +"Whether to make this column available as a [Time Granularity] option, " +"column has to be DATETIME or DATETIME-like" +msgstr "" + +#: caravel/views.py:215 +msgid "Databases" +msgstr "" + +#: caravel/views.py:217 caravel/views.py:261 caravel/views.py:284 +msgid "Sources" +msgstr "" + +#: caravel/views.py:260 +msgid "Tables" +msgstr "" + +#: caravel/views.py:282 +msgid "Druid Clusters" +msgstr "" + +#: caravel/views.py:313 +msgid "Slices" +msgstr "" + +#: caravel/views.py:341 +msgid "" +"This json object describes the positioning of the widgets in the " +"dashboard. It is dynamically generated when adjusting the widgets size " +"and positions by using drag & drop in the dashboard view" +msgstr "" + +#: caravel/views.py:346 +msgid "" +"The css for individual dashboards can be altered here, or in the " +"dashboard view where changes are immediately visible" +msgstr "" + +#: caravel/views.py:367 +msgid "Dashboards" +msgstr "" + +#: caravel/views.py:392 +msgid "Action Log" +msgstr "" + +#: caravel/views.py:393 +msgid "Security" +msgstr "Securité" + +#: caravel/views.py:430 +msgid "Druid Datasources" +msgstr "" + +#: caravel/views.py:514 +msgid "The datasource seems to have been deleted" +msgstr "" + +#: caravel/views.py:522 +msgid "You don't seem to have access to this datasource" +msgstr "" + +#: caravel/views.py:843 +msgid "This view requires the `all_datasource_access` permission" +msgstr "" + +#: caravel/views.py:954 +msgid "CSS Templates" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:34 +msgid "Profile" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:35 +msgid "Logout" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:40 +msgid "Login" +msgstr "" + +#: caravel/templates/caravel/welcome.html:8 +#: caravel/templates/caravel/welcome.html:13 +msgid "Welcome!" +msgstr "Bienvenue!" + diff --git a/caravel/translations/zh/LC_MESSAGES/messages.mo b/caravel/translations/zh/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..74d8945f3543b1edd04e4f7ec12404348ae18576 GIT binary patch literal 2352 zcmeH{&u$z=5XL7EAnbudByNC;O8_ae89R`eO>D*XZX(0_kGxBwfFSOjshw?SrhDk_ zv9q}%IDkOnz@1ZWJOP(TaO27i2_Yd4Al`rjd^Nj{6W|fDnw{TNPj%N62eY z_&tyR3;2I8#zVj2L=?4Pmvi0$pN0Jq_yPDi_#F5r_!RgT_%wLpiP@T`z-M5;1fBxV zfb#y_eEh=PUIA;2_rTY{Z^8TEZ{VBYy(ee$e*r7lzk><*?#U?n1TjAYMdxWOE_@Lb zov(tTa}gAsUxK3ZYY!sE8&Gt92a3)gKwQy}^YNeN_OGDm`~wu7dzf?|{1gy6A1F2#@3NG znTFt66FsEr(|{K~b$W!wC3**QSjimCmL{l{!@g^yF+9eLz~!ZAfMND6p*c@IqeSMfzydQ7|t}s=fGS zPUUn4u+@J8HU*g_(3EE0;+gP0#J_c1f?Fy@Q~VxP>`LuDQi^VHk=l}9j&4jCdYlxf zRJR%8kj8wUsRN~pW?P~AiryQ_9=zt1sS71-f1hk61v+~)VFEuagpPJshrQv(W>1=V z^c)xZHb*yYO_?>Xgr+kO8Z*-j7EXB#iB!OeR%d(rS`M2K!EuQZr7iWHb?f+n?BbqDZHCR(p{0=yt!qbn iHeQ={Xibf{pvCt2_Uo<3ht%Uk>hU4f9HjquNc{sO;n?i} literal 0 HcmV?d00001 diff --git a/caravel/translations/zh/LC_MESSAGES/messages.po b/caravel/translations/zh/LC_MESSAGES/messages.po new file mode 100644 index 000000000000..41bdcc006063 --- /dev/null +++ b/caravel/translations/zh/LC_MESSAGES/messages.po @@ -0,0 +1,118 @@ +# Chinese translations for PROJECT. +# Copyright (C) 2016 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2016-05-02 00:21-0700\n" +"PO-Revision-Date: 2016-05-01 23:07-0700\n" +"Last-Translator: FULL NAME \n" +"Language: zh\n" +"Language-Team: zh \n" +"Plural-Forms: nplurals=1; plural=0\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.3.4\n" + +#: caravel/models.py:564 +msgid "" +"Datetime column not provided as part table configuration and is required " +"by this type of chart" +msgstr "" + +#: caravel/models.py:1153 +msgid "No data was returned." +msgstr "" + +#: caravel/views.py:116 +msgid "" +"Whether to make this column available as a [Time Granularity] option, " +"column has to be DATETIME or DATETIME-like" +msgstr "" + +#: caravel/views.py:215 +msgid "Databases" +msgstr "" + +#: caravel/views.py:217 caravel/views.py:261 caravel/views.py:284 +msgid "Sources" +msgstr "" + +#: caravel/views.py:260 +msgid "Tables" +msgstr "" + +#: caravel/views.py:282 +msgid "Druid Clusters" +msgstr "" + +#: caravel/views.py:313 +msgid "Slices" +msgstr "" + +#: caravel/views.py:341 +msgid "" +"This json object describes the positioning of the widgets in the " +"dashboard. It is dynamically generated when adjusting the widgets size " +"and positions by using drag & drop in the dashboard view" +msgstr "" + +#: caravel/views.py:346 +msgid "" +"The css for individual dashboards can be altered here, or in the " +"dashboard view where changes are immediately visible" +msgstr "" + +#: caravel/views.py:367 +msgid "Dashboards" +msgstr "" + +#: caravel/views.py:392 +msgid "Action Log" +msgstr "" + +#: caravel/views.py:393 +msgid "Security" +msgstr "" + +#: caravel/views.py:430 +msgid "Druid Datasources" +msgstr "" + +#: caravel/views.py:514 +msgid "The datasource seems to have been deleted" +msgstr "" + +#: caravel/views.py:522 +msgid "You don't seem to have access to this datasource" +msgstr "" + +#: caravel/views.py:843 +msgid "This view requires the `all_datasource_access` permission" +msgstr "" + +#: caravel/views.py:954 +msgid "CSS Templates" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:34 +msgid "Profile" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:35 +msgid "Logout" +msgstr "" + +#: caravel/templates/appbuilder/navbar_right.html:40 +msgid "Login" +msgstr "" + +#: caravel/templates/caravel/welcome.html:8 +#: caravel/templates/caravel/welcome.html:13 +msgid "Welcome!" +msgstr "" + diff --git a/caravel/views.py b/caravel/views.py index 3a34f7a6c00d..48f203a770e7 100644 --- a/caravel/views.py +++ b/caravel/views.py @@ -13,13 +13,16 @@ import pandas as pd import sqlalchemy as sqla + from flask import ( g, request, redirect, flash, Response, render_template, Markup) from flask.ext.appbuilder import ModelView, CompactCRUDMixin, BaseView, expose from flask.ext.appbuilder.actions import action from flask.ext.appbuilder.models.sqla.interface import SQLAInterface from flask.ext.appbuilder.security.decorators import has_access +from flask.ext.babelpkg import lazy_gettext as _ from flask_appbuilder.models.sqla.filters import BaseFilter + from pydruid.client import doublesum from sqlalchemy import create_engine, select, text from sqlalchemy.sql.expression import TextAsFrom @@ -110,10 +113,10 @@ class TableColumnInlineView(CompactCRUDMixin, CaravelModelView): # noqa 'sum', 'min', 'max', 'is_dttm'] page_size = 500 description_columns = { - 'is_dttm': ( + 'is_dttm': (_( "Whether to make this column available as a " "[Time Granularity] option, column has to be DATETIME or " - "DATETIME-like"), + "DATETIME-like")), 'expression': utils.markdown( "a valid SQL expression as supported by the underlying backend. " "Example: `substr(name, 1, 1)`", True), @@ -215,8 +218,9 @@ def pre_update(self, db): appbuilder.add_view( DatabaseView, "Databases", + label=_("Databases"), icon="fa-database", - category="Sources", + category=_("Sources"), category_icon='fa-database',) @@ -259,8 +263,8 @@ def post_update(self, table): appbuilder.add_view( TableModelView, - "Tables", - category="Sources", + _("Tables"), + category=_("Sources"), icon='fa-table',) @@ -281,9 +285,9 @@ class DruidClusterModelView(CaravelModelView, DeleteMixin): # noqa if config['DRUID_IS_ACTIVE']: appbuilder.add_view( DruidClusterModelView, - "Druid Clusters", + _("Druid Clusters"), icon="fa-cubes", - category="Sources", + category=_("Sources"), category_icon='fa-database',) @@ -312,7 +316,7 @@ class SliceModelView(CaravelModelView, DeleteMixin): # noqa appbuilder.add_view( SliceModelView, - "Slices", + _("Slices"), icon="fa-bar-chart", category="", category_icon='',) @@ -340,12 +344,12 @@ class DashboardModelView(CaravelModelView, DeleteMixin): # noqa add_columns = edit_columns base_order = ('changed_on', 'desc') description_columns = { - 'position_json': ( + 'position_json': _( "This json object describes the positioning of the widgets in " "the dashboard. It is dynamically generated when adjusting " "the widgets size and positions by using drag & drop in " "the dashboard view"), - 'css': ( + 'css': _( "The css for individual dashboards can be altered here, or " "in the dashboard view where changes are immediately " "visible"), @@ -366,7 +370,9 @@ def pre_update(self, obj): appbuilder.add_view( DashboardModelView, "Dashboards", + label=_("Dashboards"), icon="fa-dashboard", + category="", category_icon='',) @@ -389,7 +395,8 @@ class LogModelView(CaravelModelView): appbuilder.add_view( LogModelView, "Action Log", - category="Security", + label=_("Action Log"), + category=_("Security"), icon="fa-list-ol") @@ -423,6 +430,7 @@ def post_update(self, datasource): appbuilder.add_view( DruidDatasourceModelView, "Druid Datasources", + label=_("Druid Datasources"), category="Sources", icon="fa-cube") @@ -506,7 +514,7 @@ def explore(self, datasource_type, datasource_id): .first() ) if not datasource: - flash("The datasource seems to have been deleted", "alert") + flash(_("The datasource seems to have been deleted"), "alert") return redirect(error_redirect) all_datasource_access = self.appbuilder.sm.has_access( @@ -514,7 +522,7 @@ def explore(self, datasource_type, datasource_id): datasource_access = self.appbuilder.sm.has_access( 'datasource_access', datasource.perm) if not (all_datasource_access or datasource_access): - flash("You don't seem to have access to this datasource", "danger") + flash(_("You don't seem to have access to this datasource"), "danger") return redirect(error_redirect) action = request.args.get('action') @@ -835,8 +843,8 @@ def runsql(self): if ( not self.appbuilder.sm.has_access( 'all_datasource_access', 'all_datasource_access')): - raise Exception( - "This view requires the `all_datasource_access` permission") + raise Exception(_( + "This view requires the `all_datasource_access` permission")) content = "" if mydb: eng = mydb.get_sqla_engine() @@ -946,6 +954,7 @@ class CssTemplateModelView(CaravelModelView, DeleteMixin): appbuilder.add_view( CssTemplateModelView, "CSS Templates", + label=_("CSS Templates"), icon="fa-css3", category="Sources", category_icon='') diff --git a/pypi_push.sh b/pypi_push.sh new file mode 100644 index 000000000000..ab234f83391b --- /dev/null +++ b/pypi_push.sh @@ -0,0 +1,6 @@ +cd caravel/assets/ +npm run prod +cd ../.. +python setup.py register +python setup.py sdist upload + diff --git a/setup.py b/setup.py index a630c0561d0a..61cd097edffa 100644 --- a/setup.py +++ b/setup.py @@ -16,8 +16,10 @@ scripts=['caravel/bin/caravel'], install_requires=[ 'alembic>=0.8.5, <0.9.0', + 'babel==2.3.4', 'cryptography>=1.1.1, <2.0.0', 'flask-appbuilder>=1.6.0, <2.0.0', + 'Flask-BabelPkg==0.9.6', 'flask-cache>=0.13.1, <0.14.0', 'flask-migrate>=1.5.1, <2.0.0', 'flask-script>=2.0.5, <3.0.0',