mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 03:20:56 -06:00
Modernize localize script, use new XML library
This file is pretty much the same as it was when it was committed in 2017; these days, we can write clearer code with async/await and new FS APIs. Additionally, we can improve the performance of this script by using a newer/faster/maintained XML library. This will enable us to run the script unconditionally in a later commit.
This commit is contained in:
parent
394c4ae68b
commit
aec2761d31
110
package-lock.json
generated
110
package-lock.json
generated
@ -25,7 +25,6 @@
|
||||
"@types/node": "latest",
|
||||
"@types/source-map-support": "latest",
|
||||
"@types/which": "^2.0.1",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@typescript-eslint/utils": "^5.33.1",
|
||||
@ -41,6 +40,7 @@
|
||||
"eslint-plugin-jsdoc": "^39.3.6",
|
||||
"eslint-plugin-local": "^1.0.0",
|
||||
"eslint-plugin-no-null": "^1.0.2",
|
||||
"fast-xml-parser": "^4.0.11",
|
||||
"fs-extra": "^9.1.0",
|
||||
"glob": "latest",
|
||||
"hereby": "^1.6.4",
|
||||
@ -53,8 +53,7 @@
|
||||
"node-fetch": "^3.2.10",
|
||||
"source-map-support": "latest",
|
||||
"typescript": "^4.8.4",
|
||||
"which": "^2.0.2",
|
||||
"xml2js": "^0.4.23"
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
@ -479,15 +478,6 @@
|
||||
"integrity": "sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/xml2js": {
|
||||
"version": "0.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.11.tgz",
|
||||
"integrity": "sha512-JdigeAKmCyoJUiQljjr7tQG3if9NkqGUgwEUqBvV0N7LM4HyQk7UXCnusRa1lnvXAEYJ8mw8GtZWioagNztOwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz",
|
||||
@ -2161,6 +2151,22 @@
|
||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz",
|
||||
"integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"strnum": "^1.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"fxparser": "src/cli/cli.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
}
|
||||
},
|
||||
"node_modules/fastest-levenshtein": {
|
||||
"version": "1.0.16",
|
||||
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
|
||||
@ -3942,12 +3948,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
@ -4124,6 +4124,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strnum": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
|
||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@ -4457,28 +4463,6 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/xml2js": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
|
||||
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
@ -4876,15 +4860,6 @@
|
||||
"integrity": "sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/xml2js": {
|
||||
"version": "0.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.11.tgz",
|
||||
"integrity": "sha512-JdigeAKmCyoJUiQljjr7tQG3if9NkqGUgwEUqBvV0N7LM4HyQk7UXCnusRa1lnvXAEYJ8mw8GtZWioagNztOwA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz",
|
||||
@ -6019,6 +5994,15 @@
|
||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-xml-parser": {
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz",
|
||||
"integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"strnum": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"fastest-levenshtein": {
|
||||
"version": "1.0.16",
|
||||
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
|
||||
@ -7264,12 +7248,6 @@
|
||||
"is-regex": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
@ -7407,6 +7385,12 @@
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"dev": true
|
||||
},
|
||||
"strnum": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
|
||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@ -7665,22 +7649,6 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"xml2js": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
|
||||
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
}
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
"@types/node": "latest",
|
||||
"@types/source-map-support": "latest",
|
||||
"@types/which": "^2.0.1",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@typescript-eslint/utils": "^5.33.1",
|
||||
@ -67,6 +66,7 @@
|
||||
"eslint-plugin-jsdoc": "^39.3.6",
|
||||
"eslint-plugin-local": "^1.0.0",
|
||||
"eslint-plugin-no-null": "^1.0.2",
|
||||
"fast-xml-parser": "^4.0.11",
|
||||
"fs-extra": "^9.1.0",
|
||||
"glob": "latest",
|
||||
"hereby": "^1.6.4",
|
||||
@ -79,8 +79,7 @@
|
||||
"node-fetch": "^3.2.10",
|
||||
"source-map-support": "latest",
|
||||
"typescript": "^4.8.4",
|
||||
"which": "^2.0.2",
|
||||
"xml2js": "^0.4.23"
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "hereby runtests-parallel --light=false",
|
||||
|
||||
@ -1,8 +1,28 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import xml2js from "xml2js";
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
|
||||
function main() {
|
||||
/** @typedef {{
|
||||
LCX: {
|
||||
$_TgtCul: string;
|
||||
Item: {
|
||||
Item: {
|
||||
Item: {
|
||||
$_ItemId: string;
|
||||
Str: {
|
||||
Val: string;
|
||||
Tgt: {
|
||||
Val: string;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
};
|
||||
};
|
||||
}
|
||||
}} ParsedLCL */
|
||||
void 0;
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length !== 3) {
|
||||
console.log("Usage:");
|
||||
@ -15,38 +35,33 @@ function main() {
|
||||
const diagnosticsMapFilePath = args[2];
|
||||
|
||||
// generate the lcg file for enu
|
||||
generateLCGFile();
|
||||
await generateLCGFile();
|
||||
|
||||
// generate other langs
|
||||
fs.readdir(inputPath, (err, files) => {
|
||||
handleError(err);
|
||||
files.forEach(visitDirectory);
|
||||
});
|
||||
const files = await fs.promises.readdir(inputPath);
|
||||
await Promise.all(files.map(visitDirectory));
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
function visitDirectory(name) {
|
||||
async function visitDirectory(name) {
|
||||
const inputFilePath = path.join(inputPath, name, "diagnosticMessages", "diagnosticMessages.generated.json.lcl");
|
||||
|
||||
fs.readFile(inputFilePath, (err, data) => {
|
||||
handleError(err);
|
||||
xml2js.parseString(data.toString(), (err, result) => {
|
||||
handleError(err);
|
||||
if (!result || !result.LCX || !result.LCX.$ || !result.LCX.$.TgtCul) {
|
||||
console.error("Unexpected XML file structure. Expected to find result.LCX.$.TgtCul.");
|
||||
process.exit(1);
|
||||
}
|
||||
const outputDirectoryName = getPreferredLocaleName(result.LCX.$.TgtCul).toLowerCase();
|
||||
if (!outputDirectoryName) {
|
||||
console.error(`Invalid output locale name for '${result.LCX.$.TgtCul}'.`);
|
||||
process.exit(1);
|
||||
}
|
||||
writeFile(path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), xmlObjectToString(result));
|
||||
});
|
||||
});
|
||||
const contents = await fs.promises.readFile(inputFilePath);
|
||||
/** @type {ParsedLCL} */
|
||||
// eslint-disable-next-line local/object-literal-surrounding-space
|
||||
const result = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "$_"}).parse(contents);
|
||||
if (!result || !result.LCX || !result.LCX.$_TgtCul) {
|
||||
console.error("Unexpected XML file structure. Expected to find result.LCX.$_TgtCul.");
|
||||
process.exit(1);
|
||||
}
|
||||
const outputDirectoryName = getPreferredLocaleName(result.LCX.$_TgtCul).toLowerCase();
|
||||
if (!outputDirectoryName) {
|
||||
console.error(`Invalid output locale name for '${result.LCX.$_TgtCul}'.`);
|
||||
process.exit(1);
|
||||
}
|
||||
await writeFile(path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), xmlObjectToString(result));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,24 +96,14 @@ function main() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {null | object} err
|
||||
*/
|
||||
function handleError(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} o
|
||||
* @param {ParsedLCL} o
|
||||
*/
|
||||
function xmlObjectToString(o) {
|
||||
/** @type {any} */
|
||||
const out = {};
|
||||
for (const item of o.LCX.Item[0].Item[0].Item) {
|
||||
let ItemId = item.$.ItemId;
|
||||
let val = item.Str[0].Tgt ? item.Str[0].Tgt[0].Val[0] : item.Str[0].Val[0];
|
||||
for (const item of o.LCX.Item.Item.Item) {
|
||||
let ItemId = item.$_ItemId;
|
||||
let val = item.Str.Tgt ? item.Str.Tgt.Val : item.Str.Val;
|
||||
|
||||
if (typeof ItemId !== "string" || typeof val !== "string") {
|
||||
console.error("Unexpected XML file structure");
|
||||
@ -115,55 +120,26 @@ function main() {
|
||||
return JSON.stringify(out, undefined, 2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} directoryPath
|
||||
* @param {() => void} action
|
||||
*/
|
||||
function ensureDirectoryExists(directoryPath, action) {
|
||||
fs.exists(directoryPath, exists => {
|
||||
if (!exists) {
|
||||
const basePath = path.dirname(directoryPath);
|
||||
if (basePath !== directoryPath) {
|
||||
return ensureDirectoryExists(basePath, () => fs.mkdir(directoryPath, action));
|
||||
}
|
||||
}
|
||||
action();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
* @param {string} contents
|
||||
*/
|
||||
function writeFile(fileName, contents) {
|
||||
ensureDirectoryExists(path.dirname(fileName), () => {
|
||||
fs.writeFile(fileName, contents, handleError);
|
||||
});
|
||||
async function writeFile(fileName, contents) {
|
||||
await fs.promises.mkdir(path.dirname(fileName), { recursive: true });
|
||||
await fs.promises.writeFile(fileName, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, string>} o
|
||||
*/
|
||||
function objectToList(o) {
|
||||
const list = [];
|
||||
for (const key in o) {
|
||||
list.push({ key, value: o[key] });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function generateLCGFile() {
|
||||
return fs.readFile(diagnosticsMapFilePath, (err, data) => {
|
||||
handleError(err);
|
||||
writeFile(
|
||||
path.join(outputPath, "enu", "diagnosticMessages.generated.json.lcg"),
|
||||
getLCGFileXML(
|
||||
objectToList(JSON.parse(data.toString()))
|
||||
.sort((a, b) => a.key > b.key ? 1 : -1) // lcg sorted by property keys
|
||||
.reduce((s, { key, value }) => s + getItemXML(key, value), "")
|
||||
));
|
||||
});
|
||||
async function generateLCGFile() {
|
||||
const contents = await fs.promises.readFile(diagnosticsMapFilePath, "utf-8");
|
||||
await writeFile(
|
||||
path.join(outputPath, "enu", "diagnosticMessages.generated.json.lcg"),
|
||||
getLCGFileXML(
|
||||
Object.entries(JSON.parse(contents))
|
||||
.sort((a, b) => a[0] > b[0] ? 1 : -1) // lcg sorted by property keys
|
||||
.reduce((s, [key, value]) => s + getItemXML(key, value), "")
|
||||
),
|
||||
);
|
||||
return;
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
@ -204,4 +180,4 @@ function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
await main();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user