Source code for timApp.admin.language_cli

"""
Enables adding Languages to TIM's database from the command line
"""

__authors__ = [
    "Noora Jokela",
    "Riku Lehkonen",
    "Vili Moisala",
    "Juho Tarkkanen",
    "Sami Viitanen",
]
__license__ = "MIT"
__date__ = "8.4.2022"

import click
import langcodes
from flask.cli import AppGroup

from timApp.document.translation.language import Language
from timApp.tim_app import app
from timApp.timdb.sqa import db
from timApp.util.logger import log_error, log_info, log_debug

language_cli = AppGroup("language")


@language_cli.command()
@click.argument("lang_code")
def remove(lang_code: str) -> None:
    """
    Remove a specific language from the database by specifying its language code.

    :param lang_code: IETF language tag for the language.
    :return: None
    """

    exists = Language.query.filter(lang_code == Language.lang_code).first()
    if exists:
        if click.confirm("This action cannot be reversed. Continue?"):
            click.echo(
                f"Removing language '{exists.lang_name} ({exists.lang_code})' from the database."
            )
            db.session.delete(exists)
            db.session.commit()
        else:
            click.echo("Removal of language aborted by user.")
    else:
        click.echo(f"Language code '{lang_code}' could not be found in the database.")


@language_cli.command()
@click.argument("lang_name")
def add(lang_name: str) -> None:
    """
    Add a standard language to the language database based on the language name.

    :param lang_name: Natural name of the language.
    :return: None
    """

    try:
        lang = Language.create_from_name(lang_name)
    except Exception as e:
        click.echo(f"Failed to create language: {str(e)}")
        return

    exists = Language.query.filter(lang.lang_code == Language.lang_code).first()
    if exists:
        click.echo(f"Language code '{lang.lang_code}' already exists in the database.")
    else:
        click.echo(f"Adding new language '{lang.lang_name} ({lang.lang_code})'")
        db.session.add(lang)
        db.session.commit()


@language_cli.command()
def add_all_languages() -> None:
    """
    Add languages defined in configuration into database from command line.

    :return: None.
    """
    add_all_supported_languages(True)


[docs]def add_all_supported_languages(log: bool = False) -> None: """ Add all supported languages to the database. Supported languages are defined in the configuration variable LANGUAGES in timApp\defaultconfig.py. This separate function allows adding all the languages at the db-initialization. :return: None. """ # Add to the database the languages found in config and skip existing ones. langset = {x[0] for x in Language.query.with_entities(Language.lang_code).all()} for l in app.config["LANGUAGES"]: if type(l) is dict: lang = Language( lang_code=l["lang_code"], lang_name=l["lang_name"], autonym=l["autonym"], ) else: try: lang = Language.create_from_name(l) except Exception as e: log_error(f"Failed to create language: {str(e)}") click.echo(f"Failed to create language: {str(e)}") if lang.lang_code not in langset: # TODO Are these logs unnecessary? log_debug(f"Adding new language '{lang.lang_name} ({lang.lang_code})'") if log: click.echo(f"Adding new language '{lang.lang_name} ({lang.lang_code})'") db.session.add(lang) else: log_info( f"Skipping language '{lang.lang_name} ({lang.lang_code})': Already in database" ) if log: click.echo( f"Language code '{lang.lang_code}' already exists in the database." ) db.session.commit()
@language_cli.command() @click.option("--langcode", prompt="IETF language tag") @click.option("--langname", prompt="Natural name for the language in English") @click.option("--autonym", prompt="Native name for the language") @click.option("--flag_uri", prompt="URI for an image file", default="") def create(langcode: str, langname: str, autonym: str, flag_uri: str) -> None: """ Creates a new custom language and adds it to the database. :param langcode: IETF custom language tag. :param langname: Natural name for the language in English. :param autonym: Native name for the language. :param flag_uri: Optional URI for an image file, representing the country of the language. :return: None """ # Standardize the primary key with langcodes before inserting into db. # Note: variant name must not exceed 8 characters in length. # Example: "en-gibberis" is acceptable while "en-gibberish" is not. try: standard_code = langcodes.standardize_tag(langcode) valid = langcodes.tag_is_valid(standard_code) if not valid: click.echo( f"Invalid custom language code {standard_code}. Code must be a valid IETF language tag." ) return except Exception as e: click.echo(f"Failed to create new language: {str(e)}") return exists = Language.query.filter(standard_code == Language.lang_code).first() if exists: click.echo(f"Language code '{standard_code}' already exists in the database.") else: click.echo(f"Creating new language '{langname} ({standard_code})'") lang = Language( lang_code=standard_code, lang_name=langname, autonym=autonym, flag_uri=flag_uri, ) click.echo("New custom language created.") db.session.add(lang) db.session.commit() click.echo( f"Custom language '{langname} ({standard_code})' has been added to the database." )