# coding=utf-8
# -*- coding: UTF-8 -*-
#
# Copyright 2015-2025, Vincenzo Arcidiacono;
# Licensed under the EUPL (the 'Licence');
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
"""
It provides functions to build the language service.
"""
import os
import functools
import os.path as osp
from flask_babel import Babel, Domain
from werkzeug.exceptions import NotFound
from werkzeug.datastructures.accept import LanguageAccept
from flask import (
jsonify, current_app, request, session, Blueprint, send_from_directory
)
bp = Blueprint('locales', __name__)
[docs]
@functools.lru_cache()
def get_domain(domain):
return Domain(domain=domain)
[docs]
def lazy_gettext(*args, domain=None, **kwargs):
return get_domain(domain).lazy_gettext(*args, **kwargs)
[docs]
@bp.route('/<language>/<namespace>', methods=['GET'])
def locales(language, namespace):
for d in current_app.extensions['babel'].translation_directories:
try:
return send_from_directory(
d, f'{osp.join(language, "LC_MESSAGES", namespace)}.po',
as_attachment=True
)
except NotFound:
pass
raise NotFound()
[docs]
@bp.route('/languages.json', methods=['GET'])
def get_locales():
return jsonify(current_app.config.get('BABEL_LANGUAGES'))
[docs]
def _set_locale(languages):
get = current_app.config.get
session['locale'] = locale = languages.best_match(
get('BABEL_LANGUAGES'), get('BABEL_DEFAULT_LOCALE')
)
return locale
[docs]
@bp.route('/<lang>', methods=['POST'])
def set_locale(lang):
languages = LanguageAccept([(lang, 2)] + request.accept_languages)
return jsonify({"language": _set_locale(languages)})
[docs]
@bp.route('/<lang>', methods=['GET'])
def get_locale(lang):
locale = session.get('locale')
if not locale:
return set_locale(lang)
return jsonify({"language": locale})
[docs]
def _get_locale():
return session.get('locale') or _set_locale(request.accept_languages)
[docs]
class Locales:
[docs]
def __init__(self, app, *args, **kwargs):
if app is not None:
self.init_app(app, *args, **kwargs)
[docs]
def init_app(self, app, *args, locale_selector=_get_locale, **kwargs):
app.extensions = getattr(app, 'extensions', {})
app.config['BABEL_DEFAULT_LOCALE'] = app.config.get(
'BABEL_DEFAULT_LOCALE', os.environ.get(
'BABEL_DEFAULT_LOCALE', 'en_US'
)
)
app.config['BABEL_LANGUAGES'] = app.config.get(
'BABEL_LANGUAGES', {
'af_ZA': {"icon": "🇿🇦", "label": "Afrikaans"},
'ca_ES': {"icon": "🇪🇸", "label": "Català"},
'da_DK': {"icon": "🇩🇰", "label": "Dansk"},
'de_DE': {"icon": "🇩🇪", "label": "Deutsch"},
'en_US': {"icon": "🇺🇸", "label": "English"},
'es_ES': {"icon": "🇪🇸", "label": "Español"},
'eu_ES': {"icon": "🇪🇸", "label": "Euskara"},
'fr_FR': {"icon": "🇫🇷", "label": "Français"},
'hu_HU': {"icon": "🇭🇺", "label": "Magyar"},
'hy_AM': {"icon": "🇦🇲", "label": "Հայերեն"},
'is_IS': {"icon": "🇮🇸", "label": "Íslenska"},
'it_IT': {"icon": "🇮🇹", "label": "Italiano"},
'ja_JP': {"icon": "🇯🇵", "label": "日本語"},
'nl_NL': {"icon": "🇳🇱", "label": "Nederlands"},
'pl_PL': {"icon": "🇵🇱", "label": "Polski"},
'pt_BR': {"icon": "🇧🇷", "label": "Português (Brasil)"},
'pt_PT': {"icon": "🇵🇹", "label": "Português (Portugal)"},
'ru_RU': {"icon": "🇷🇺", "label": "Русский"},
'tr_TR': {"icon": "🇹🇷", "label": "Türkçe"},
'zh_Hans_CN': {"icon": "🇨🇳", "label": "中文(简体)"}
}
)
directories = []
it = app.config.get(
'BABEL_TRANSLATION_DIRECTORIES',
os.environ.get('BABEL_TRANSLATION_DIRECTORIES', 'translations')
)
if isinstance(it, str):
it = [it]
for k in it:
directories.extend(k.split(';'))
if not directories:
directories.append('translations')
tdir = osp.join(osp.dirname(__file__), 'translations')
if tdir not in directories:
directories.append(tdir)
app.config['BABEL_TRANSLATION_DIRECTORIES'] = ';'.join(directories)
Babel(app, *args, locale_selector=locale_selector, **kwargs)
app.register_blueprint(bp, url_prefix='/locales')
app.extensions['locates'] = self