gpii-windows
Version:
Components of the GPII personalization infrastructure for use on Microsoft's "Windows" ™
147 lines (129 loc) • 5.34 kB
JavaScript
/*
* 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
*/
;
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);
});