140 lines
4.7 KiB
TypeScript
140 lines
4.7 KiB
TypeScript
|
import * as fs from "fs";
|
||
|
import * as path from "path";
|
||
|
import * as xml2js from "xml2js";
|
||
|
|
||
|
function main(): void {
|
||
|
const args = process.argv.slice(2);
|
||
|
if (args.length !== 3) {
|
||
|
console.log("Usage:");
|
||
|
console.log("\tnode generateLocalizedDiagnosticMessages.js <lcl source directory> <output directory> <generated diagnostics map file>");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const inputPath = args[0];
|
||
|
const outputPath = args[1];
|
||
|
const diagnosticsMapFilePath = args[2];
|
||
|
|
||
|
// generate the lcg file for enu
|
||
|
generateLCGFile();
|
||
|
|
||
|
// generate other langs
|
||
|
fs.readdir(inputPath, (err, files) => {
|
||
|
handleError(err);
|
||
|
files.forEach(visitDirectory);
|
||
|
});
|
||
|
|
||
|
return;
|
||
|
|
||
|
function visitDirectory(name: string) {
|
||
|
const inputFilePath = path.join(inputPath, name, "diagnosticMessages", "diagnosticMessages.generated.json.lcl");
|
||
|
const outputFilePath = path.join(outputPath, name, "diagnosticMessages.generated.json");
|
||
|
fs.readFile(inputFilePath, (err, data) => {
|
||
|
handleError(err);
|
||
|
xml2js.parseString(data.toString(), (err, result) => {
|
||
|
handleError(err);
|
||
|
writeFile(outputFilePath, xmlObjectToString(result));
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function handleError(err: null | object) {
|
||
|
if (err) {
|
||
|
console.error(err);
|
||
|
process.exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function xmlObjectToString(o: any) {
|
||
|
const out: any = {};
|
||
|
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];
|
||
|
|
||
|
if (typeof ItemId !== "string" || typeof Val !== "string") {
|
||
|
console.error("Unexpected XML file structure");
|
||
|
process.exit(1);
|
||
|
}
|
||
|
|
||
|
if (ItemId.charAt(0) === ";") {
|
||
|
ItemId = ItemId.slice(1); // remove leading semicolon
|
||
|
}
|
||
|
|
||
|
Val = Val.replace(/]5D;/, "]"); // unescape `]`
|
||
|
out[ItemId] = Val;
|
||
|
}
|
||
|
return JSON.stringify(out, undefined, 2);
|
||
|
}
|
||
|
|
||
|
|
||
|
function ensureDirectoryExists(directoryPath: string, action: () => void) {
|
||
|
fs.exists(directoryPath, exists => {
|
||
|
if (!exists) {
|
||
|
const basePath = path.dirname(directoryPath);
|
||
|
if (basePath !== directoryPath) {
|
||
|
return ensureDirectoryExists(basePath, () => fs.mkdir(directoryPath, action));
|
||
|
}
|
||
|
}
|
||
|
action();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function writeFile(fileName: string, contents: string) {
|
||
|
ensureDirectoryExists(path.dirname(fileName), () => {
|
||
|
fs.writeFile(fileName, contents, handleError);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function objectToList(o: Record<string, string>) {
|
||
|
const list: { key: string, value: string }[] = [];
|
||
|
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), "")
|
||
|
));
|
||
|
});
|
||
|
|
||
|
function getItemXML(key: string, value: string) {
|
||
|
// escape entrt value
|
||
|
value = value.replace(/]/, "]5D;");
|
||
|
|
||
|
return `
|
||
|
<Item ItemId=";${key}" ItemType="0" PsrId="306" Leaf="true">
|
||
|
<Str Cat="Text">
|
||
|
<Val><![CDATA[${value}]]></Val>
|
||
|
</Str>
|
||
|
<Disp Icon="Str" />
|
||
|
</Item>`;
|
||
|
}
|
||
|
|
||
|
function getLCGFileXML(items: string) {
|
||
|
return `<?xml version="1.0" encoding="utf-8"?>
|
||
|
<LCX SchemaVersion="6.0" Name="diagnosticMessages.generated.json" PsrId="306" FileType="1" SrcCul="en-US" xmlns="http://schemas.microsoft.com/locstudio/2006/6/lcx">
|
||
|
<OwnedComments>
|
||
|
<Cmt Name="Dev" />
|
||
|
<Cmt Name="LcxAdmin" />
|
||
|
<Cmt Name="Rccx" />
|
||
|
</OwnedComments>
|
||
|
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
|
||
|
<Disp Icon="Expand" Expand="true" Disp="true" LocTbl="false" />
|
||
|
<Item ItemId=";Strings" ItemType="0" PsrId="306" Leaf="false">
|
||
|
<Disp Icon="Str" Disp="true" LocTbl="false" />${items}
|
||
|
</Item>
|
||
|
</Item>
|
||
|
</LCX>`;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
main();
|