<commit_before>/*
 * Windows Language
 *
 * Copyright 2018 Raising the Floor - International
 *
 * Licensed under the New BSD license. You may not use this file except in
 * compliance with this License.
 *
 * The R&D leading to these results received funding from the
 * Department of Education - Grant H421A150005 (GPII-APCP). However,
 * these results do not necessarily represent the policy of the
 * Department of Education, and you should not assume endorsement by the
 * Federal Government.
 *
 * You may obtain a copy of the License at
 * https://github.com/GPII/universal/blob/master/LICENSE.txt
 */

"use strict";

var fluid = require("gpii-universal"),
    child_process = require("child_process");

var gpii = fluid.registerNamespace("gpii");

fluid.registerNamespace("gpii.windows.language");

fluid.defaults("gpii.windows.language", {
    gradeNames: ["fluid.component", "fluid.modelComponent"],
    invokers: {
        getInstalledLanguages: {
            funcName: "gpii.windows.language.getInstalled",
            args: [ "{that}" ]
        },
        getLanguageNames: {
            funcName: "gpii.windows.language.getLanguageNames",
            args: [ "{that}", "{arguments}.0" ]
        },
        getDisplayLanguage: {
            funcName: "gpii.windows.language.getDisplayLanguage"
        },
        startMessages: "{gpii.windows.messages}.start({that})",
        stopMessages: "{gpii.windows.messages}.stop({that})"
    },
    listeners: {
        "onCreate.update": "{that}.getInstalledLanguages()",
        "onCreate.messages": "{that}.startMessages()",
        "{gpii.windows.messages}.events.onMessage": {
            funcName: "gpii.windows.language.windowMessage",
            // that, hwnd, msg, wParam, lParam
            args: [ "{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2", "{arguments}.3" ]
        }
    },
    // The model gets updated whenever getInstalledLanguages is called.
    model: {
        /** @type {Map<String,InstalledLanguage>} */
        installedLanguages: null,
        /** Currently configured display language */
        configuredLanguage: null
    },
    members: {
        /** code=>name map of language names in english */
        englishNames: {}
    }
});

/**
 * Language names.
 * @typedef {Object} LanguageNames
 * @property {String} english The language name in English.
 * @property {String} local The language name (and country), in the current display language.
 * @property {String} native The language name (and country), in its native language.
 */

/**
 * An installed language
 * @typedef {LanguageNames} InstalledLanguage
 * @property {String} code The language code, `lang[-COUNTRY]`.
 * @property {Boolean} current true if this is the current display language.
 */

/**
 * Gets the display languages that are installed on the system, and updates the model.
 *
 * These are listed in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MUI\UILanguages
 *
 * @param {Component} that The gpii.windows.language instance.
 * @return {Promise<Map<String,InstalledLanguage>>} A promise, resolving with either the language names if the list has
 * changed, or null if there was no change.
 */
gpii.windows.language.getInstalled = function (that) {
    var langCodes = gpii.windows.enumRegistryKeys(
        "HKEY_LOCAL_MACHINE", "SYSTEM\\CurrentControlSet\\Control\\MUI\\UILanguages");

    var knownLanguages = Object.keys(that.model.installedLanguages || {});
    var changed = langCodes.length !== knownLanguages.length;
    if (!changed) {
        changed = !knownLanguages.every(function (elem) {
            return langCodes.includes(elem);
        });
    }

    var p;
    if (changed) {
        p = that.getLanguageNames(langCodes).then(function (languages) {
            var current = gpii.windows.language.getDisplayLanguage();

            that.applier.change("installedLanguages", languages);
            that.applier.change("configuredLanguage", current);
        });
    } else {
        p = fluid.promise().resolve();
    }

    return p;
};

/**
 * Gets the language names of the given languages, identified by their IETF language codes (`en`, `es-MX`).
 *
 * It returns an object containing the name in English, the current display language, and native language.
 *
 * If only the language identifier (first 2 characters) are passed, then the language name is returned.
 * If the country code is also given, then the country is also returned in brackets:
 *  - If the country is code is unknown, or the country-specific language isn't recognised, then the language code is
 *     used instead of the country.
 *  - If the language is only spoken in a single country (eg, Bulgarian), then the country is not returned, unless a
 *     different country was passed (eg, bg-GB).
 * If the language is unknown, then an empty string is used. If the language code is invalid, null each field is null.
 *
 * Examples:
 *```
 * "es-MX" => { english: "Spanish (Mexico)", local: "Spanish (Mexico)", native: "Español (México)" }<commit_msg>GPII-3544: Always applying the configuredLanguage<commit_after>/*
 * Windows Language
 *
 * Copyright 2018 Raising the Floor - International
 *
 * Licensed under the New BSD license. You may not use this file except in
 * compliance with this License.
 *
 * The R&D leading to these results received funding from the
 * Department of Education - Grant H421A150005 (GPII-APCP). However,
 * these results do not necessarily represent the policy of the
 * Department of Education, and you should not assume endorsement by the
 * Federal Government.
 *
 * You may obtain a copy of the License at
 * https://github.com/GPII/universal/blob/master/LICENSE.txt
 */

"use strict";

var fluid = require("gpii-universal"),
    child_process = require("child_process");

var gpii = fluid.registerNamespace("gpii");

fluid.registerNamespace("gpii.windows.language");

fluid.defaults("gpii.windows.language", {
    gradeNames: ["fluid.component", "fluid.modelComponent"],
    invokers: {
        getInstalledLanguages: {
            funcName: "gpii.windows.language.getInstalled",
            args: [ "{that}" ]
        },
        getLanguageNames: {
            funcName: "gpii.windows.language.getLanguageNames",
            args: [ "{that}", "{arguments}.0" ]
        },
        getDisplayLanguage: {
            funcName: "gpii.windows.language.getDisplayLanguage"
        },
        startMessages: "{gpii.windows.messages}.start({that})",
        stopMessages: "{gpii.windows.messages}.stop({that})"
    },
    listeners: {
        "onCreate.update": "{that}.getInstalledLanguages()",
        "onCreate.messages": "{that}.startMessages()",
        "{gpii.windows.messages}.events.onMessage": {
            funcName: "gpii.windows.language.windowMessage",
            // that, hwnd, msg, wParam, lParam
            args: [ "{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2", "{arguments}.3" ]
        }
    },
    // The model gets updated whenever getInstalledLanguages is called.
    model: {
        /** @type {Map<String,InstalledLanguage>} */
        installedLanguages: null,
        /** Currently configured display language */
        configuredLanguage: null
    },
    members: {
        /** code=>name map of language names in english */
        englishNames: {}
    }
});

/**
 * Language names.
 * @typedef {Object} LanguageNames
 * @property {String} english The language name in English.
 * @property {String} local The language name (and country), in the current display language.
 * @property {String} native The language name (and country), in its native language.
 */

/**
 * An installed language
 * @typedef {LanguageNames} InstalledLanguage
 * @property {String} code The language code, `lang[-COUNTRY]`.
 * @property {Boolean} current true if this is the current display language.
 */

/**
 * Gets the display languages that are installed on the system, and updates the model.
 *
 * These are listed in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MUI\UILanguages
 *
 * @param {Component} that The gpii.windows.language instance.
 * @return {Promise<Map<String,InstalledLanguage>>} A promise, resolving with either the language names if the list has
 * changed, or null if there was no change.
 */
gpii.windows.language.getInstalled = function (that) {
    var langCodes = gpii.windows.enumRegistryKeys(
        "HKEY_LOCAL_MACHINE", "SYSTEM\\CurrentControlSet\\Control\\MUI\\UILanguages");

    var knownLanguages = Object.keys(that.model.installedLanguages || {});
    var changed = langCodes.length !== knownLanguages.length;
    if (!changed) {
        changed = !knownLanguages.every(function (elem) {
            return langCodes.includes(elem);
        });
    }

    var current = gpii.windows.language.getDisplayLanguage();
    var promise;
    if (changed) {
        // Update the language names only if required.
        promise = that.getLanguageNames(langCodes).then(function (languages) {
            that.applier.change("installedLanguages", languages);
        });
    } else {
        promise = fluid.promise().resolve();
    }

    promise.then(function () {
        that.applier.change("configuredLanguage", current);
    });

    return promise;
};

/**
 * Gets the language names of the given languages, identified by their IETF language codes (`en`, `es-MX`).
 *
 * It returns an object containing the name in English, the current display language, and native language.
 *
 * If only the language identifier (first 2 characters) are passed, then the language name is returned.
 * If the country code is also given, then the country is also returned in brackets:
 *  - If the country is code is unknown, or the country-specific language isn't recognised, then the language code is
 *     used instead of the country.
 *  - If the language is only spoken in a single country (eg, Bulgarian), then the country is not returned, unless a
 *     different country was passed (eg, bg-GB).
 * If the language is unknown, then an empty string is used. If the language code is invalid, null each field is null.
 *
 * Examples:
 *```
 * "es-MX" => { english: "Spanish (Mexico)", local: "Spanish (Mexico)", native: "Español (México)" }
{'fraction_non_alphanumeric': 0.11806780325298843, 'fraction_numerical': 0.00411522633744856, 'mean_word_length': 3.1969572368421053, 'pattern_counts': {'":': 6, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1080616', 'n_tokens_mistral': 2844, 'n_tokens_neox': 2772, 'n_words': 918}