Locale selector UI works

This commit is contained in:
Piero Toffanin 2023-01-06 10:27:39 -05:00
parent aa5936dae5
commit 754ac65b9e
7 changed files with 71 additions and 18 deletions

View file

@ -1 +1 @@
1.3.8 1.3.9

View file

@ -19,7 +19,7 @@ from flask_babel import Babel
from libretranslate import flood, remove_translated_files, security from libretranslate import flood, remove_translated_files, security
from libretranslate.language import detect_languages, improve_translation_formatting from libretranslate.language import detect_languages, improve_translation_formatting
from libretranslate.locales import (_, _lazy, get_available_locales, gettext_escaped, from libretranslate.locales import (_, _lazy, get_available_locales, get_available_locale_codes, gettext_escaped,
gettext_html, lazy_swag, get_alternate_locale_links) gettext_html, lazy_swag, get_alternate_locale_links)
from .api_keys import Database, RemoteDatabase from .api_keys import Database, RemoteDatabase
@ -287,6 +287,7 @@ def create_app(args):
version=get_version(), version=get_version(),
swagger_url=SWAGGER_URL, swagger_url=SWAGGER_URL,
url_prefix=args.url_prefix, url_prefix=args.url_prefix,
available_locales=[{'code': l['code'], 'name': _lazy(l['name'])} for l in get_available_locales()],
current_locale=get_locale(), current_locale=get_locale(),
alternate_locales=get_alternate_locale_links() alternate_locales=get_alternate_locale_links()
) )
@ -1013,7 +1014,7 @@ def create_app(args):
babel = Babel(app) babel = Babel(app)
@babel.localeselector @babel.localeselector
def get_locale(): def get_locale():
return request.accept_languages.best_match(get_available_locales()) return request.accept_languages.best_match(get_available_locale_codes())
app.jinja_env.globals.update(_e=gettext_escaped, _h=gettext_html) app.jinja_env.globals.update(_e=gettext_escaped, _h=gettext_html)

View file

@ -7,11 +7,30 @@ from flask_babel import lazy_gettext as _lazy
from markupsafe import escape, Markup from markupsafe import escape, Markup
@cache @cache
def get_available_locales(): def get_available_locales(only_reviewed=True):
locales_dir = os.path.join(os.path.dirname(__file__), 'locales') locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
dirs = [os.path.join(locales_dir, d) for d in os.listdir(locales_dir)] dirs = [os.path.join(locales_dir, d) for d in os.listdir(locales_dir)]
return ['en'] + [os.path.basename(d) for d in dirs if os.path.isdir(os.path.join(d, 'LC_MESSAGES'))] res = [{'code': 'en', 'name': 'English'}]
for d in dirs:
meta_file = os.path.join(d, 'meta.json')
if os.path.isdir(os.path.join(d, 'LC_MESSAGES')) and os.path.isfile(meta_file):
try:
with open(meta_file) as f:
j = json.loads(f.read())
except Exception as e:
print(e)
continue
if j.get('reviewed') or not only_reviewed:
res.append({'code': os.path.basename(d), 'name': j.get('name', '')})
return res
@cache
def get_available_locale_codes(only_reviewed=True):
return [l['code'] for l in get_available_locales(only_reviewed=only_reviewed)]
@cache @cache
def get_alternate_locale_links(): def get_alternate_locale_links():
@ -19,7 +38,7 @@ def get_alternate_locale_links():
if tmpl is None: if tmpl is None:
return [] return []
locales = get_available_locales() locales = get_available_locale_codes()
result = [] result = []
for l in locales: for l in locales:
link = tmpl.replace("{LANG}", l) link = tmpl.replace("{LANG}", l)

View file

@ -0,0 +1,4 @@
{
"name": "Italian",
"reviewed": true
}

View file

@ -52,6 +52,21 @@ h3.header {
box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%), 0px 4px 5px 0 rgb(0 0 0 / 20%); box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%), 0px 4px 5px 0 rgb(0 0 0 / 20%);
} }
.locale-panel{
display: none;
}
#nav:hover #change-language:hover + .locale-panel,
#nav-mobile:hover #change-language:hover + .locale-panel{
display: block;
}
#nav:hover .locale-panel:hover,
#nav-mobile .locale-panel:hover{
display: block;
}
.locale-panel select{ .locale-panel select{
display: block; display: block;
height: 32px; height: 32px;
@ -65,6 +80,12 @@ h3.header {
padding: 0; padding: 0;
margin-top: 6px; margin-top: 6px;
text-align: right; text-align: right;
text-decoration: none;
height: 28px;
}
.locale-panel a:hover{
text-decoration: underline;
} }
.locale-panel a i.material-icons{ .locale-panel a i.material-icons{
@ -84,6 +105,7 @@ h3.header {
#nav-mobile .locale-panel{ #nav-mobile .locale-panel{
color: rgba(0,0,0,0.87); color: rgba(0,0,0,0.87);
padding: 0 32px; padding: 0 32px;
padding-top: 12px;
} }
#nav-mobile .locale-panel a{ #nav-mobile .locale-panel a{

View file

@ -62,7 +62,7 @@
<img src="{{ url_for('static', filename='icon.svg') }}" alt="LibreTranslate" class="logo"> <img src="{{ url_for('static', filename='icon.svg') }}" alt="LibreTranslate" class="logo">
<span>LibreTranslate</span> <span>LibreTranslate</span>
</a> </a>
<ul class="right hide-on-med-and-down top-nav position-relative"> <ul id="nav" class="right hide-on-med-and-down top-nav position-relative">
{% set menulinks %} {% set menulinks %}
<li><a href="{{ swagger_url }}">{{ _h("API Docs") }}</a></li> <li><a href="{{ swagger_url }}">{{ _h("API Docs") }}</a></li>
{% if get_api_key_link %} {% if get_api_key_link %}
@ -72,14 +72,13 @@
{% if api_keys %} {% if api_keys %}
<li><a class="noline" href="javascript:setApiKey()" title="{{ _h('Set API Key') }}"><i class="material-icons">vpn_key</i></a></li> <li><a class="noline" href="javascript:setApiKey()" title="{{ _h('Set API Key') }}"><i class="material-icons">vpn_key</i></a></li>
{% endif %} {% endif %}
<li><a class="noline" href="#" title="{{ _h('Change language') }}"><i class="material-icons">language</i></a> <li id="change-language"><a class="noline" href="javascript:void(0)" title="{{ _h('Change language') }}"><i class="material-icons">language</i></a>
</li> </li>
<li class="locale-panel"> <li class="locale-panel" id="locale-panel">
<select id="locales"> <select id="locales">
<option value="en">English</option> {% for l in available_locales %}<option value="{{ l['code'] }}" {{ 'selected' if current_locale == l['code'] else ''}}>{{ l['name'] }}</option>{% endfor %}
<option value="it">Italian</option>
</select> </select>
<a href="#">Improve this language<i class="material-icons">create</i></a> <a href="#TODO">{{ _h("Edit") }}<i class="material-icons">create</i></a>
</li> </li>
{% endset %} {% endset %}
{{ menulinks }} {{ menulinks }}

View file

@ -6,7 +6,7 @@ import polib
import json import json
from babel.messages.frontend import main as pybabel from babel.messages.frontend import main as pybabel
from libretranslate.language import load_languages, improve_translation_formatting from libretranslate.language import load_languages, improve_translation_formatting
from libretranslate.locales import get_available_locales, swag_eval from libretranslate.locales import get_available_locale_codes, swag_eval
from translatehtml import translate_html from translatehtml import translate_html
from libretranslate.app import get_version, create_app from libretranslate.app import get_version, create_app
from libretranslate.main import get_args from libretranslate.main import get_args
@ -58,10 +58,8 @@ if __name__ == "__main__":
"-o", messagespot, "libretranslate"] "-o", messagespot, "libretranslate"]
pybabel() pybabel()
lang_codes = [l.code for l in languages if l != "en"] lang_codes = [l.code for l in languages if l != "en"]
lang_codes = ["it"] # TODO REMOVE lang_codes = ["it", "fr"] # TODO REMOVE
# Init/update # Init/update
for l in lang_codes: for l in lang_codes:
@ -71,14 +69,24 @@ if __name__ == "__main__":
sys.argv = ["", cmd, "-i", messagespot, "-d", locales_dir, "-l", l] sys.argv = ["", cmd, "-i", messagespot, "-d", locales_dir, "-l", l]
pybabel() pybabel()
meta_file = os.path.join(locales_dir, l, "meta.json")
if not os.path.isfile(meta_file):
with open(meta_file, 'w') as f:
f.write(json.dumps({
'name': next((lang.name for lang in languages if lang.code == l)),
'reviewed': False
}, indent=4))
print("Wrote %s" % meta_file)
# Automatically translate strings with libretranslate # Automatically translate strings with libretranslate
# when a language model is available and a string is empty # when a language model is available and a string is empty
locales = get_available_locales() locales = get_available_locale_codes(only_reviewed=False)
print(locales)
for locale in locales: for locale in locales:
if locale == 'en': if locale == 'en':
continue continue
tgt_lang = next((l for l in languages if l.code == locale), None) tgt_lang = next((l for l in languages if l.code == locale), None)