Toollabs/video2commons

View on GitHub
video2commons/frontend/i18n.py

Summary

Maintainability
A
1 hr
Test Coverage
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2015-2016 Zhuyifei1999
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>
#

"""video2commons web i18n module."""



import os
import json

from flask import Blueprint, Response, request, session, g
from video2commons.frontend.shared import redisconnection

i18nblueprint = Blueprint('i18n', __name__)

_d = os.path.dirname(os.path.realpath(__file__))


@i18nblueprint.after_request
def max_age(response):
    """Set max_age of response to 5 mins."""
    response.cache_control.max_age = 3600
    return response


@i18nblueprint.route('/<lang>')
def urlget(lang):
    """Get the i18n of language lang and output Javascript."""
    data = 'window.i18n=' + json.dumps(get(lang)) + ';'
    return Response(data, mimetype='application/javascript; charset=utf-8')


def get(lang):
    """Get the i18n of language lang and output dict."""
    i18nkey = 'i18n:' + lang
    gval = g.get(i18nkey, None)
    if gval:
        return gval
    if redisconnection.exists(i18nkey):
        return json.loads(redisconnection.get(i18nkey))

    data = {}
    fallbacklist = _create_fallback(lang)
    datafiles = _loadi18nfiles(fallbacklist)
    for key in datafiles['en']:
        if key == '@metadata':
            # @metadata is a dict not a string
            continue

        for code in fallbacklist:
            if key in datafiles.get(code, {}):
                data[key] = datafiles[code][key]
                # <'s and >'s aren't supposed to be here;
                # if the translation breaks due to double escaping,
                # oh well, why are you hacking this tool?
                # --XSS prevention
                data[key] = data[key].replace('<', '&lt;')
                data[key] = data[key].replace('>', '&gt;')
                break
    data['@lang'] = lang
    data['@dir'] = _dir(lang)

    setattr(g, i18nkey, data)
    redisconnection.setex(i18nkey, 60, json.dumps(data))
    return data


def _loadi18nfiles(fallbacklist):
    datafiles = {}
    for code in fallbacklist:
        if code not in datafiles:
            path = _d + '/i18n/' + code + '.json'
            if os.path.isfile(path):
                with open(path, 'r') as f:
                    datafiles[code] = json.load(f)
    return datafiles


def _create_fallback(lang):
    fallbacks = _loadmetadatafile('fallbacks').get(lang, [])
    fallbacks = fallbacks if isinstance(fallbacks, list) else [fallbacks]
    return [lang] + fallbacks + ['en']


def translate(key):
    """Translate a key in user language."""
    return get(getlanguage()).get(key, '&lt;' + key + '&gt;')


def getlanguage():
    """Get the user language."""
    gval = g.get('language', None)
    if gval:
        return gval

    for lang in [
        request.form.get('uselang'),
        request.args.get('uselang'),
        session.get('language'),
        request.accept_languages.best,
    ]:
        if lang and _islang(lang):
            break
    else:
        lang = 'en'

    g.language = lang

    return lang


def _loadmetadatafile(metadata):
    key = 'i18nmeta-' + metadata
    gval = g.get(key, None)
    if gval:
        return gval

    path = _d + '/i18n-metadata/' + metadata + '.json'
    with open(path, 'r') as f:
        data = json.load(f)

    setattr(g, key, data)
    return data


def _islang(lang):
    return lang in _loadmetadatafile('alllangs')


def _dir(lang):
    return 'rtl' if lang in _loadmetadatafile('rtl') else 'ltr'


def is_rtl(lang):
    """Jinja2 test for rtl-ness."""
    return get(lang).get('@dir') == 'rtl'