pogen: read files from tsconfig, import po2ts
This commit is contained in:
parent
aa7d48bfb1
commit
e6c1294c91
@ -11,6 +11,7 @@
|
|||||||
"compile": "tsc"
|
"compile": "tsc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"po2json": "^0.4.5",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.5.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
const ts = require("typescript");
|
|
||||||
|
|
||||||
const configPath = ts.findConfigFile(
|
|
||||||
/*searchPath*/ "./",
|
|
||||||
ts.sys.fileExists,
|
|
||||||
"tsconfig.json"
|
|
||||||
);
|
|
||||||
if (!configPath) {
|
|
||||||
throw new Error("Could not find a valid 'tsconfig.json'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(configPath);
|
|
||||||
|
|
||||||
const cmdline = ts.getParsedCommandLineOfConfigFile(configPath, {}, {
|
|
||||||
fileExists: ts.sys.fileExists,
|
|
||||||
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
||||||
onUnRecoverableConfigFileDiagnostic: (e) => console.log(e),
|
|
||||||
readDirectory: ts.sys.readDirectory,
|
|
||||||
readFile: ts.sys.readFile,
|
|
||||||
useCaseSensitiveFileNames: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(cmdline);
|
|
||||||
|
|
||||||
const prog = ts.createProgram({
|
|
||||||
options: cmdline.options,
|
|
||||||
rootNames: cmdline.fileNames,
|
|
||||||
});
|
|
||||||
|
|
||||||
const allFiles = prog.getSourceFiles();
|
|
||||||
|
|
||||||
console.log(allFiles.map(x => x.path));
|
|
60
packages/pogen/src/po2ts.ts
Normal file
60
packages/pogen/src/po2ts.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2020 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a <lang>.po file into a JavaScript / TypeScript expression.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import * as po2json from "po2json";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
const files = fs
|
||||||
|
.readdirSync("./src/i18n")
|
||||||
|
.filter((x) => x.endsWith(".po"))
|
||||||
|
.map((x) => path.join("./src/i18n/", x));
|
||||||
|
|
||||||
|
if (files.length === 0) {
|
||||||
|
console.error("no .po files found in src/i18n/");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(files);
|
||||||
|
|
||||||
|
const chunks: string[] = [];
|
||||||
|
|
||||||
|
for (const filename of files) {
|
||||||
|
const m = filename.match(/([a-zA-Z0-9-_]+).po/);
|
||||||
|
|
||||||
|
if (!m) {
|
||||||
|
console.error("error: unexpected filename (expected <lang>.po)");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const lang = m[1];
|
||||||
|
const pojson = po2json.parseFileSync(filename, {
|
||||||
|
format: "jed1.x",
|
||||||
|
fuzzy: true,
|
||||||
|
});
|
||||||
|
const s =
|
||||||
|
"strings['" + lang + "'] = " + JSON.stringify(pojson, null, " ") + ";\n\n";
|
||||||
|
chunks.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tsContents = chunks.join("");
|
||||||
|
|
||||||
|
fs.writeFileSync("src/i18n/strings.ts", tsContents);
|
@ -1,32 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of GNU Taler
|
||||||
(C) 2016 GNUnet e.V.
|
(C) 2019-2022 Taler Systems S.A.
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU General Public License as published by the Free Software
|
terms of the GNU General Public License as published by the Free Software
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate .po file from list of source files.
|
|
||||||
*
|
|
||||||
* Note that duplicate message IDs are NOT merged, to get the same output as
|
|
||||||
* you would from xgettext, just run msguniq.
|
|
||||||
*
|
|
||||||
* @author Florian Dold
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { readFileSync } from "fs";
|
|
||||||
import * as ts from "typescript";
|
import * as ts from "typescript";
|
||||||
|
|
||||||
function wordwrap(str: string, width: number = 80): string[] {
|
function wordwrap(str: string, width: number = 80): string[] {
|
||||||
@ -34,7 +25,7 @@ function wordwrap(str: string, width: number = 80): string[] {
|
|||||||
return str.match(RegExp(regex, "g"));
|
return str.match(RegExp(regex, "g"));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processFile(sourceFile: ts.SourceFile) {
|
export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) {
|
||||||
processNode(sourceFile);
|
processNode(sourceFile);
|
||||||
let lastTokLine = 0;
|
let lastTokLine = 0;
|
||||||
let preLastTokLine = 0;
|
let preLastTokLine = 0;
|
||||||
@ -146,11 +137,11 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
function formatMsgComment(line: number, comment?: string) {
|
function formatMsgComment(line: number, comment?: string) {
|
||||||
if (comment) {
|
if (comment) {
|
||||||
for (let cl of comment.split("\n")) {
|
for (let cl of comment.split("\n")) {
|
||||||
console.log(`#. ${cl}`);
|
outChunks.push(`#. ${cl}\n`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`#: ${sourceFile.fileName}:${line + 1}`);
|
outChunks.push(`#: ${sourceFile.fileName}:${line + 1}\n`);
|
||||||
console.log(`#, c-format`);
|
outChunks.push(`#, c-format\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMsgLine(head: string, msg: string) {
|
function formatMsgLine(head: string, msg: string) {
|
||||||
@ -161,11 +152,11 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
.map((p) => wordwrap(p))
|
.map((p) => wordwrap(p))
|
||||||
.reduce((a, b) => a.concat(b));
|
.reduce((a, b) => a.concat(b));
|
||||||
if (parts.length == 1) {
|
if (parts.length == 1) {
|
||||||
console.log(`${head} "${parts[0]}"`);
|
outChunks.push(`${head} "${parts[0]}"\n`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`${head} ""`);
|
outChunks.push(`${head} ""\n`);
|
||||||
for (let p of parts) {
|
for (let p of parts) {
|
||||||
console.log(`"${p}"`);
|
outChunks.push(`"${p}"\n`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +199,7 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
switch (childNode.kind) {
|
switch (childNode.kind) {
|
||||||
case ts.SyntaxKind.JsxText: {
|
case ts.SyntaxKind.JsxText: {
|
||||||
let e = childNode as ts.JsxText;
|
let e = childNode as ts.JsxText;
|
||||||
let s = e.getFullText();
|
let s = e.text;
|
||||||
let t = s.split("\n").map(trim).join(" ");
|
let t = s.split("\n").map(trim).join(" ");
|
||||||
if (s[0] === " ") {
|
if (s[0] === " ") {
|
||||||
t = " " + t;
|
t = " " + t;
|
||||||
@ -295,8 +286,8 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
let comment = getComment(node);
|
let comment = getComment(node);
|
||||||
formatMsgComment(line, comment);
|
formatMsgComment(line, comment);
|
||||||
formatMsgLine("msgid", content);
|
formatMsgLine("msgid", content);
|
||||||
console.log(`msgstr ""`);
|
outChunks.push(`msgstr ""\n`);
|
||||||
console.log();
|
outChunks.push("\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (arrayEq(path, ["i18n", "TranslateSwitch"])) {
|
if (arrayEq(path, ["i18n", "TranslateSwitch"])) {
|
||||||
@ -315,9 +306,9 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
}
|
}
|
||||||
formatMsgLine("msgid", singularForm);
|
formatMsgLine("msgid", singularForm);
|
||||||
formatMsgLine("msgid_plural", pluralForm);
|
formatMsgLine("msgid_plural", pluralForm);
|
||||||
console.log(`msgstr[0] ""`);
|
outChunks.push(`msgstr[0] ""\n`);
|
||||||
console.log(`msgstr[1] ""`);
|
outChunks.push(`msgstr[1] ""\n`);
|
||||||
console.log();
|
outChunks.push(`\n`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -346,25 +337,24 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
formatMsgComment(line, comment);
|
formatMsgComment(line, comment);
|
||||||
formatMsgLine("msgid", t1.template);
|
formatMsgLine("msgid", t1.template);
|
||||||
formatMsgLine("msgid_plural", t2.template);
|
formatMsgLine("msgid_plural", t2.template);
|
||||||
console.log(`msgstr[0] ""`);
|
outChunks.push(`msgstr[0] ""\n`);
|
||||||
console.log(`msgstr[1] ""`);
|
outChunks.push(`msgstr[1] ""\n`);
|
||||||
console.log();
|
outChunks.push("\n");
|
||||||
|
|
||||||
// Important: no processing for child i18n expressions here
|
// Important: no processing for child i18n expressions here
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ts.SyntaxKind.TaggedTemplateExpression: {
|
case ts.SyntaxKind.TaggedTemplateExpression: {
|
||||||
let tte = <ts.TaggedTemplateExpression>node;
|
let tte = <ts.TaggedTemplateExpression>node;
|
||||||
let { comment, template, line, path } = processTaggedTemplateExpression(
|
let { comment, template, line, path } =
|
||||||
tte,
|
processTaggedTemplateExpression(tte);
|
||||||
);
|
|
||||||
if (path[0] != "i18n") {
|
if (path[0] != "i18n") {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
formatMsgComment(line, comment);
|
formatMsgComment(line, comment);
|
||||||
formatMsgLine("msgid", template);
|
formatMsgLine("msgid", template);
|
||||||
console.log(`msgstr ""`);
|
outChunks.push(`msgstr ""\n`);
|
||||||
console.log();
|
outChunks.push("\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,36 +363,51 @@ export function processFile(sourceFile: ts.SourceFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
const configPath = ts.findConfigFile(
|
||||||
const configPath = ts.findConfigFile(
|
/*searchPath*/ "./",
|
||||||
/*searchPath*/ "./",
|
ts.sys.fileExists,
|
||||||
ts.sys.fileExists,
|
"tsconfig.json",
|
||||||
"tsconfig.json",
|
);
|
||||||
);
|
if (!configPath) {
|
||||||
if (!configPath) {
|
throw new Error("Could not find a valid 'tsconfig.json'.");
|
||||||
throw new Error("Could not find a valid 'tsconfig.json'.");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const cmdline = ts.getParsedCommandLineOfConfigFile(
|
console.log(configPath);
|
||||||
configPath,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
fileExists: ts.sys.fileExists,
|
|
||||||
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
||||||
onUnRecoverableConfigFileDiagnostic: (e) => console.log(e),
|
|
||||||
readDirectory: ts.sys.readDirectory,
|
|
||||||
readFile: ts.sys.readFile,
|
|
||||||
useCaseSensitiveFileNames: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const fileNames = cmdline.fileNames;
|
const cmdline = ts.getParsedCommandLineOfConfigFile(
|
||||||
|
configPath,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
fileExists: ts.sys.fileExists,
|
||||||
|
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
||||||
|
onUnRecoverableConfigFileDiagnostic: (e) => console.log(e),
|
||||||
|
readDirectory: ts.sys.readDirectory,
|
||||||
|
readFile: ts.sys.readFile,
|
||||||
|
useCaseSensitiveFileNames: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
fileNames.sort();
|
console.log(cmdline);
|
||||||
|
|
||||||
const outChunks: string[] = [];
|
const prog = ts.createProgram({
|
||||||
|
options: cmdline.options,
|
||||||
|
rootNames: cmdline.fileNames,
|
||||||
|
});
|
||||||
|
|
||||||
outChunks.push(`# SOME DESCRIPTIVE TITLE.
|
const allFiles = prog.getSourceFiles();
|
||||||
|
|
||||||
|
const ownFiles = allFiles.filter(
|
||||||
|
(x) =>
|
||||||
|
!x.isDeclarationFile &&
|
||||||
|
!prog.isSourceFileFromExternalLibrary(x) &&
|
||||||
|
!prog.isSourceFileDefaultLibrary(x),
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(ownFiles.map((x) => x.fileName));
|
||||||
|
|
||||||
|
const chunks = [];
|
||||||
|
|
||||||
|
chunks.push(`# SOME DESCRIPTIVE TITLE.
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
@ -421,16 +426,8 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\\n"
|
"Content-Type: text/plain; charset=UTF-8\\n"
|
||||||
"Content-Transfer-Encoding: 8bit\\n"`);
|
"Content-Transfer-Encoding: 8bit\\n"`);
|
||||||
|
|
||||||
fileNames.forEach((fileName) => {
|
for (const f of ownFiles) {
|
||||||
let sourceFile = ts.createSourceFile(
|
processFile(f, chunks);
|
||||||
fileName,
|
|
||||||
readFileSync(fileName).toString(),
|
|
||||||
ts.ScriptTarget.ES2016,
|
|
||||||
/*setParentNodes */ true,
|
|
||||||
);
|
|
||||||
processFile(sourceFile);
|
|
||||||
});
|
|
||||||
|
|
||||||
const out = outChunks.join("");
|
|
||||||
console.log(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(chunks.join(""));
|
@ -10,5 +10,5 @@
|
|||||||
"lib": ["es6"],
|
"lib": ["es6"],
|
||||||
"types": ["node"]
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"files": ["pogen.ts"]
|
"include": ["src/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
@ -150,10 +150,12 @@ importers:
|
|||||||
packages/pogen:
|
packages/pogen:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@types/node': ^17.0.17
|
'@types/node': ^17.0.17
|
||||||
|
po2json: ^0.4.5
|
||||||
typescript: ^4.5.5
|
typescript: ^4.5.5
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 17.0.17
|
'@types/node': 17.0.17
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
po2json: 0.4.5
|
||||||
typescript: 4.5.5
|
typescript: 4.5.5
|
||||||
|
|
||||||
packages/taler-util:
|
packages/taler-util:
|
||||||
|
Loading…
Reference in New Issue
Block a user