UNPKG

gpii-windows

Version:

Components of the GPII personalization infrastructure for use on Microsoft's "Windows" ™

147 lines (129 loc) 5.34 kB
/* * Child process to get localised language names. * * Set the GPII_LANG_CODES environment variable to a json array containing the desired language-country codes. * * This needs to be performed in a child process in order to use the system's current display language. Loading and * unloading winlangdb in the main process did not appear to work. GPII-3544. * * 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 ffi = require("ffi-napi"), ref = require("ref"); /** * winlangdb.dll is used by control panel to perform language-related things. The first parameter of these functions * are a pointer to a HSTRING containing the language code (en-US), the second is a pointer which will * contain a pointer a HSTRING to the result when it returns. (These are undocumented). */ var winlangdb = ffi.Library("winlangdb", { // Get the english name of a language code. // HRESULT Bcp47GetEnglishName(HSTRING, HSTRING*) "Bcp47GetEnglishName": [ "int", [ "int", "int*" ] ], // Get the localised name of a language code. // HRESULT Bcp47GetLocalizedName(HSTRING, HSTRING*) "Bcp47GetLocalizedName": [ "int", [ "int", "int*" ] ], // Get the native name of a language code. // HRESULT Bcp47GetNativeName(HSTRING, HSTRING*) "Bcp47GetNativeName": [ "int", [ "int", "int*" ] ] }); var crtString = ffi.Library("api-ms-win-core-winrt-string-l1-1-0.dll", { // https://docs.microsoft.com/windows/desktop/api/winstring/nf-winstring-windowscreatestring "WindowsCreateString": [ "int", [ "void*", "int", "int*" ] ], // https://docs.microsoft.com/windows/desktop/api/winstring/nf-winstring-windowsgetstringrawbuffer "WindowsGetStringRawBuffer": [ "char*", ["int", "int*"] ], // https://docs.microsoft.com/en-us/windows/desktop/api/winstring/nf-winstring-windowsdeletestring "WindowsDeleteString": [ "int", ["int"] ] }); /** * Gets the language names of the given language, identified by its IETF language code (`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 unknown, then an empty string is used. If the language code is invalid, null each field is null. * * Examples: *``` * "es-MX" => { english: "Spanish", local: "Spanish (Mexico)", native: "Español (México)" } * "en" => { english: "English", local: "English", native: "English" } * "en-GB" => { "english": "English", "local": "English (United Kingdom)", "native": "English (United Kingdom)" } *``` * When the current display language is French: * ``` * "nl-NL" => { english: "Dutch", local: "Néerlandais (Pays-Bas)", native: "Nederlands (Nederland)" } * ``` * @param {String} langCode The language codes, in the form of `lang[-COUNTRY]`. * @return {LanguageNames} The language names. */ function getLanguageNames(langCode) { // Create a HSTRING from the language code. var codeBuf = new Buffer(langCode + "\u0000", "ucs2"); var codeHStr = ref.alloc("int"); crtString.WindowsCreateString(codeBuf, langCode.length, codeHStr); var funcs = { "english": winlangdb.Bcp47GetEnglishName, "local": winlangdb.Bcp47GetLocalizedName, "native": winlangdb.Bcp47GetNativeName }; var result = {}; Object.keys(funcs).forEach(function (key) { var func = funcs[key]; var name = null; var nameHStr = ref.alloc("int"); var errorCode = func(codeHStr.deref(), nameHStr); if (errorCode) { console.error("Bcp47GetXXXName failed (" + key + ")", errorCode); } else { var len = ref.alloc("int"); var nameBuffer = crtString.WindowsGetStringRawBuffer(nameHStr.deref(), len); if (len.deref() > 0) { name = ref.reinterpretUntilZeros(nameBuffer, 2, 0).toString("ucs2"); } else { name = ""; } } crtString.WindowsDeleteString(nameHStr.deref()); result[key] = name; }); crtString.WindowsDeleteString(codeHStr); return result; } var langCodes = JSON.parse(process.env.GPII_LANG_CODES); var result = {}; langCodes.forEach(function (langCode) { result[langCode] = getLanguageNames(langCode); }); process.send(result, function (err) { if (err) { console.error("Failed to send language names", err); } process.exit(err ? 1 : 0); });