-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathlanguageNames.js
More file actions
146 lines (129 loc) · 5.22 KB
/
languageNames.js
File metadata and controls
146 lines (129 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* 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-napi");
/**
* 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);
});