added translations support
This commit is contained in:
parent
92865d8783
commit
fc28212ce0
@ -1 +1,2 @@
|
||||
email,password,role_names
|
||||
admin@blog.pi2.dev,__SENSITIVE__.ADMIN_PASSWORD,admin
|
|
5
bootstrap/translations/babel.cfg
Normal file
5
bootstrap/translations/babel.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
[ignore: venv/**]
|
||||
[ignore: migrations/**]
|
||||
[python: **.py]
|
||||
[jinja2: **/templates/**.html]
|
||||
extensions=jinja2.ext.autoescape,jinja2.ext.with_
|
@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Project</title>
|
||||
<title>{{ _("Project") }}</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "Open Sans", Arial, sans-serif;
|
||||
|
@ -1,9 +1,9 @@
|
||||
<a href="{{ url_for('home') }}">Home</a> |
|
||||
<a href="{{ url_for('home') }}">{{ _("Home") }}</a> |
|
||||
<div class="pull-right">
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="#">{{ current_user.email }}</a> |
|
||||
<a href="{{ url_for('security.logout') }}">Logout</a> |
|
||||
<a href="{{ url_for('security.logout') }}">{{ _("Logout") }}</a> |
|
||||
{% else %}
|
||||
<a href="{{ url_for('security.login') }}">Login</a> |
|
||||
<a href="{{ url_for('security.login') }}">{{ _("Login") }}</a> |
|
||||
{% endif %}
|
||||
</div>
|
24
bootstrap/webapp/view_models/Example.yaml_
Normal file
24
bootstrap/webapp/view_models/Example.yaml_
Normal file
@ -0,0 +1,24 @@
|
||||
# RENAME THIS FILE TO .yaml and use the structure below
|
||||
#
|
||||
name: Example # name of the model
|
||||
searchable: # list of columns that are searchable
|
||||
- body
|
||||
interits: # list of inheritable classes, each line is one of (Ownable|Datable)
|
||||
- Ownable
|
||||
access:
|
||||
- verb: all
|
||||
login_required: true
|
||||
roles_required:
|
||||
- admin
|
||||
- verb: get
|
||||
login_required: false
|
||||
- verb: list
|
||||
login_required: false
|
||||
- verb: table
|
||||
login_required: false
|
||||
- verb: search
|
||||
login_required: false
|
||||
columns:
|
||||
- name: filename
|
||||
- name: body
|
||||
type: long_text
|
@ -35,8 +35,6 @@ Usage $0 [ bootstrap | model | db_migrate | db_upgrade | db_populate | db_recrea
|
||||
cert [DOMAIN] Install certificate
|
||||
"
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
HELP_TRANSLATION="
|
||||
USAGE ./manage.sh translate [extract|gen {lang}|compile|update]
|
||||
|
||||
@ -47,8 +45,10 @@ USAGE ./manage.sh translate [extract|gen {lang}|compile|update]
|
||||
"
|
||||
|
||||
command_translate() {
|
||||
shift
|
||||
TRANSLATE_COMMAND=$1
|
||||
shift
|
||||
source venv/bin/activate
|
||||
case "$TRANSLATE_COMMAND" in
|
||||
extract) pybabel extract -F translations/babel.cfg -o translations/messages.pot .
|
||||
;;
|
||||
@ -154,6 +154,9 @@ bootstrap() {
|
||||
python manager.py db migrate -m "001"
|
||||
_post_migrate
|
||||
python manager.py db upgrade
|
||||
git init .
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
}
|
||||
|
||||
run_in_prod() {
|
||||
|
@ -7,6 +7,9 @@ from importlib import import_module
|
||||
from json import JSONEncoder
|
||||
from uuid import uuid4
|
||||
|
||||
from flask import request
|
||||
from flask_security import current_user
|
||||
|
||||
from config import SQLALCHEMY_DATABASE_URI, MAKEDIRS, DATABASE_FILE, SEARCH_INDEX_PATH, STATIC_DATA_DIR, basepath
|
||||
from flask_migrate import Migrate
|
||||
from flask_migrate import upgrade as migrate_upgrade
|
||||
@ -21,7 +24,7 @@ from sqlalchemy import TypeDecorator
|
||||
from sqlalchemy.ext.declarative import declared_attr, DeclarativeMeta
|
||||
from sqlalchemy.orm.collections import InstrumentedList
|
||||
from sqlalchemy_utils import Choice
|
||||
from tww.lib import solve_query, resolve_timezone, dt_tz_translation, time_ago
|
||||
from tww.lib import solve_query, resolve_timezone, dt_tz_translation, time_ago, get_utcnow
|
||||
from whooshalchemy import IndexService
|
||||
from oshipka.util.strings import camel_case_to_snake_case
|
||||
from vm_gen.vm_gen import order_from_process_order
|
||||
@ -40,6 +43,11 @@ class Ownable(object):
|
||||
return db.relationship("User")
|
||||
|
||||
|
||||
class Datable(object):
|
||||
created_dt = db.Column(db.UnicodeText())
|
||||
updated_dt = db.Column(db.UnicodeText())
|
||||
|
||||
|
||||
roles_users = db.Table('roles_users',
|
||||
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
|
||||
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
|
||||
@ -236,11 +244,35 @@ def register_index_svc():
|
||||
index_service.proxied.register_class(searchable)
|
||||
|
||||
|
||||
def _init_translations(app):
|
||||
from flask_babelex import Babel
|
||||
babel = Babel(app)
|
||||
|
||||
@babel.localeselector
|
||||
def get_locale():
|
||||
# if a user is logged in, use the locale from the user settings
|
||||
if current_user.is_authenticated:
|
||||
return current_user.locale
|
||||
# otherwise try to guess the language from the user accept
|
||||
# header the browser transmits
|
||||
return request.accept_languages.best_match(app.config.get('TRANSLATION_LANGUAGES', ['en']))
|
||||
|
||||
@babel.timezoneselector
|
||||
def get_timezone():
|
||||
if current_user is not None:
|
||||
return current_user.timezone
|
||||
|
||||
|
||||
def init_db(app):
|
||||
rv = False
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
|
||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||
app.config["WHOOSH_BASE"] = SEARCH_INDEX_PATH
|
||||
try:
|
||||
from config import TRANSLATION_LANGUAGES
|
||||
app.config["TRANSLATION_LANGUAGES"] = TRANSLATION_LANGUAGES
|
||||
except:
|
||||
app.config["TRANSLATION_LANGUAGES"] = ['en']
|
||||
|
||||
from oshipka.webapp import test_bp, oshipka_bp
|
||||
app.register_blueprint(test_bp)
|
||||
@ -249,6 +281,7 @@ def init_db(app):
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
security.init_app(app, user_datastore)
|
||||
_init_translations(app)
|
||||
|
||||
register_filters(app)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
from sqlalchemy_utils import ChoiceType
|
||||
[%- endif %]
|
||||
|
||||
class [[ name ]](db.Model, ModelController):
|
||||
class [[ name ]](db.Model, ModelController[% for inherit in interits %], [[ inherit ]][% endfor %]):
|
||||
[%- include "_model_choice_header_py" %]
|
||||
[%- include "_model_searchable_header_py" %]
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<table>
|
||||
[%- for column in columns %]
|
||||
<tr><td>
|
||||
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>:
|
||||
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">{{ _("[[ column.name ]]") }}</label>:
|
||||
</td><td>
|
||||
[%- if column.type in ['relationship'] %]
|
||||
[% if column.multiple %]
|
||||
@ -12,7 +12,7 @@
|
||||
<select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]" name="[[ column.name ]]_id">
|
||||
[%- endif %]
|
||||
[%- if not column.secondary %]
|
||||
<option selected="selected" value="">Choose...</option>
|
||||
<option selected="selected" value="">{{ _("Choose...") }}</option>
|
||||
[%- endif %]
|
||||
{% if instance and instance.[[ column.name|pluralize ]] is defined %}
|
||||
{% set [[ column.name|pluralize ]] = instance.[[ column.name|pluralize ]] %}
|
||||
@ -26,7 +26,7 @@
|
||||
[%- elif column.type in ['choice', ] %]
|
||||
<select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
|
||||
name="[[ column.name ]]">
|
||||
<option selected="selected" value="">Choose...</option>
|
||||
<option selected="selected" value="">{{ _("Choose...") }}</option>
|
||||
[%- for value, display in column.choices.items() %]
|
||||
<option value="[[ value ]]" {% if instance and instance.[[ column.name ]] == "[[ value ]]" %}selected="selected"{% endif %}>[[ display ]]</option>
|
||||
[%- endfor %]
|
||||
@ -40,6 +40,9 @@
|
||||
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
|
||||
type="checkbox" value="1" name="_[[ column.name ]]"
|
||||
/>
|
||||
[%- elif column.type in ['long_text', ] %]
|
||||
<textarea id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
|
||||
name="[[ column.name ]]"></textarea>
|
||||
[%- else %]
|
||||
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
|
||||
type="text" name="[[ column.name ]]" autocomplete="off"
|
||||
|
@ -7,14 +7,14 @@
|
||||
</video>
|
||||
[%- elif column.type in ['relationship'] %]
|
||||
[%- if column.multiple %]
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name|pluralize ]]</strong>: {{ instance.[[ column.name|pluralize ]] }}</li>
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>{{ _("[[ column.name|pluralize ]]") }}</strong>: {{ instance.[[ column.name|pluralize ]] }}</li>
|
||||
[%- else %]
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]] }}</li>
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>{{_("[[ column.name ]]") }}</strong>: {{ instance.[[ column.name ]] }}</li>
|
||||
[%- endif %]
|
||||
[%- elif column.type in ['bool', 'boolean', ] %]
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]]|bool }}</li>
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>{{ _("[[ column.name ]]") }}</strong>: {{ instance.[[ column.name ]]|bool }}</li>
|
||||
[%- else %]
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]] }}</li>
|
||||
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>{{ _("[[ column.name ]]") }}</strong>: {{ instance.[[ column.name ]] }}</li>
|
||||
[%- endif %]
|
||||
{% endif %}
|
||||
[%- endfor %]
|
@ -3,10 +3,10 @@
|
||||
<tr>
|
||||
[%- for column in columns %]
|
||||
{% if "[[ column.name ]]" not in skip_columns %}
|
||||
<th>[[ column.name ]]</th>
|
||||
<th>{{ _("[[ column.name ]]") }}</th>
|
||||
{% endif %}
|
||||
[%- endfor %]
|
||||
<th>Actions</th>
|
||||
<th>{{ _("Actions") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -6,5 +6,5 @@
|
||||
- {{ instance.[[ display.secondary ]] }}
|
||||
[%- endif %]
|
||||
[%- else %]
|
||||
[[ name ]] {{ instance.id }}
|
||||
{{ _("[[ name ]]") }} {{ instance.id }}
|
||||
[%- endif %]
|
@ -3,7 +3,7 @@
|
||||
<table>
|
||||
[%- for column in columns %]
|
||||
<tr><td>
|
||||
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>:
|
||||
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">{{ _("[[ column.name ]]") }}</label>:
|
||||
</td><td>
|
||||
[%- if column.type in ['relationship'] %]
|
||||
[%- if column.multiple %]
|
||||
@ -39,6 +39,9 @@
|
||||
type="checkbox" name="_[[ column.name ]]" {% if instance.[[ column.name ]] %}checked=checked{% endif %}
|
||||
value="1"
|
||||
/>
|
||||
[%- elif column.type in ['long_text', ] %]
|
||||
<textarea id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
|
||||
name="[[ column.name ]]">{{ instance.[[ column.name ]] }}</textarea>
|
||||
[%- else %]
|
||||
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
|
||||
value="{{ instance.[[ column.name ]] }}"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Create [[ name ]]</h2>
|
||||
<h2>{{ _("Create") }} {{_("[[ name ]]") }}</h2>
|
||||
{% include "[[ name|camel_to_snake ]]/_create.html" %}
|
||||
{% endblock %}
|
@ -1,9 +1,9 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<a href="{{ url_for('list_[[ name|camel_to_snake ]]', uuid=instance.id) }}">list</a> |
|
||||
<a href="{{ url_for('list_[[ name|camel_to_snake ]]', uuid=instance.id) }}">{{ _("list") }}</a> |
|
||||
<h2>{% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
|
||||
<a href="{{ url_for('update_[[ name|camel_to_snake ]]', uuid=instance.id, _next=request.path) }}">edit</a> |
|
||||
<a href="{{ url_for('delete_[[ name|camel_to_snake ]]', uuid=instance.id) }}">delete</a>
|
||||
<a href="{{ url_for('update_[[ name|camel_to_snake ]]', uuid=instance.id, _next=request.path) }}">{{ _("edit") }}</a> |
|
||||
<a href="{{ url_for('delete_[[ name|camel_to_snake ]]', uuid=instance.id) }}">{{ _("delete") }}</a>
|
||||
{% include "[[ name|camel_to_snake ]]/_get.html" %}
|
||||
{% endblock %}
|
@ -1,8 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>[[ name|pluralize ]]</h2>
|
||||
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">Create</a>
|
||||
<h2>{{ _("[[ name|pluralize ]]") }}</h2>
|
||||
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">{{ _("Create") }}</a>
|
||||
<br>
|
||||
{% include "[[ name|camel_to_snake ]]/_list.html" %}
|
||||
{% endblock %}
|
@ -1,8 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Search results for [[ name|pluralize ]]</h2>
|
||||
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">Create</a>
|
||||
<h2>{{ _("Search results for") }} {{ _("[[ name|pluralize ]]") }}</h2>
|
||||
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">{{ _("Create") }}</a>
|
||||
<br>
|
||||
{% include "[[ name|camel_to_snake ]]/_search.html" %}
|
||||
{% endblock %}
|
@ -1,8 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>[[ name|pluralize ]]</h2>
|
||||
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">Create</a>
|
||||
<h2>{{ _("[[ name|pluralize ]]") }}</h2>
|
||||
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">{{ _("Create") }}</a>
|
||||
<br>
|
||||
{% include "[[ name|camel_to_snake ]]/_table.html" %}
|
||||
{% endblock %}
|
@ -1,6 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Edit {% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
|
||||
<h2>{{ _("Edit") }} {% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
|
||||
{% include "[[ name|camel_to_snake ]]/_update.html" %}
|
||||
{% endblock %}
|
@ -1,4 +1,4 @@
|
||||
from oshipka.persistance import db, ModelController, index_service, LiberalBoolean
|
||||
from oshipka.persistance import db, ModelController, index_service, LiberalBoolean[% for inherit in interits %], [[ inherit ]][% endfor %]
|
||||
|
||||
[%- if imports %]
|
||||
[%- for import in imports %]
|
||||
|
Loading…
Reference in New Issue
Block a user