/*
 * This file is part of the Amalthea library.
 * Copyright (C) 2018-2022, 2024 Eugene 'Vindex' Stulin
 * Distributed under the BSL 1.0 or the GNU LGPL 3.0 or later.
 */

/**
 * The module implements the simplest system
 * for creating language localizations.
 */
module amalthea.langlocal;

import std.array, std.process;

public import amalthea.libcore;
import amalthea.csv;


static string[][] localeStrings;
static string[string] langconformity;
static string currentLanguage = "en_US";


/*******************************************************************************
 * Current system language.
 */
string getSystemLanguage() {
    auto lang = environment.get("LANG", "en_US.UTF-8");
    return lang.split(".")[0];
}


/*******************************************************************************
 * Current application language by langlocal settings.
 */
string getCurrentLanguage() {
    return currentLanguage;
}


/*******************************************************************************
 * Initializes localization by a two-dimensional array of strings.
 * Titles of columns (first line - index 0) must be locales
 * in Linux style without encoding (en_US, en_GB, eo, fr_CA, ru_RU, etc.),
 * first locale is en_US always.
 *
 * Params:
 *     stringsWithLocalizations = Two-dimensional array containing columns
 *                                of strings in different languages.
 *     language = New current language (system language by default).
 *
 */
void initLocalization(
    in string[][] stringsWithLocalizations,
    string language = ""
) {
    localeStrings = cast(string[][])stringsWithLocalizations;
    if (localeStrings[0][0] != "en_US") {
        throw new LocalizationsTableException(
            "Error: array in cell [0][0] must consist en_US"
        );
    }
    if (language == "") {
        language = getSystemLanguage;
    }
    chooseLanguage(language);
}


/*******************************************************************************
 * Initializes localization by a CSV file with translations.
 * Titles of columns (first line - index 0) must be locales in Linux style
 * without encoding (en_US, en_GB, eo, fr_CA, ru_RU, etc.),
 * first locale is en_US always.
 *
 * Params:
 *     csvPath = A path to a CSV file with translations.
 *     language = A new current language (system language by default).
 *
 */
void initLocalization(string csvPath, string language = "") {
    auto csv = CSV(csvPath);
    initLocalization(csv.getTable(), language);
}


/*******************************************************************************
 * This function allows to choose current locale for application.
 */
void chooseLanguage(string language) {
    if (localeStrings.empty) return;
    foreach(i, locale; localeStrings[0]) {
        if (language != locale) continue;
        currentLanguage = language;
        size_t currentTableColumn = i;
        foreach(row; localeStrings) {
            if (row[currentTableColumn] == "") {
                langconformity[row[0]] = row[0];
            } else {
                langconformity[row[0]] = row[currentTableColumn];
            }
        }
        return;
    }
    currentLanguage = "en_US";
}


/*******************************************************************************
 * This function returns string corresponding to the English (en_US) version,
 * according to the current localization selected.
 */
string s_(string englishString) {
    return langconformity.get(englishString, englishString);
}
alias _s = s_;


unittest {
    initLocalization([
        ["en_US",    "ru_RU",     "eo"],
        ["Hello",    "Привет",    "Saluton"],
        ["Orange",   "Апельсин",  "Oranĝo"],
        ["Language", "Язык",      "Lingvo"],
        ["Computer", "Компьютер", "Komputilo"]
    ]);

    chooseLanguage("ru_RU");
    assert(s_("Orange") == "Апельсин");
    assert("Untranslated string"._s == "Untranslated string");
    assert("Other text" == "Other text".s_);

    chooseLanguage("eo");
    assert("Language"._s == "Lingvo");
    chooseLanguage("Quenya");  // invalid
    assert(getCurrentLanguage == "en_US");
}


/*******************************************************************************
 * Exception for incorrect localization tables.
 */
class LocalizationsTableException : Exception {
    this(string msg) {
        super(msg);
    }
}

