diff options
Diffstat (limited to 'packages/pogen')
-rwxr-xr-x | packages/pogen/bin/pogen | 2 | ||||
-rw-r--r-- | packages/pogen/example/proj1/package.json | 5 | ||||
-rw-r--r-- | packages/pogen/example/proj1/src/i18n/test.pot (renamed from packages/pogen/example/messages.po) | 105 | ||||
-rw-r--r-- | packages/pogen/example/proj1/src/test.ts (renamed from packages/pogen/example/test.ts) | 3 | ||||
-rw-r--r-- | packages/pogen/example/proj1/src/test2.tsx (renamed from packages/pogen/example/test2.tsx) | 2 | ||||
-rw-r--r-- | packages/pogen/example/proj1/tsconfig.json | 2 | ||||
-rw-r--r-- | packages/pogen/package.json | 10 | ||||
-rw-r--r-- | packages/pogen/po2.js | 32 | ||||
-rw-r--r-- | packages/pogen/src/dumpTree.ts (renamed from packages/pogen/dumpTree.ts) | 0 | ||||
-rw-r--r-- | packages/pogen/src/po2ts.ts | 146 | ||||
-rw-r--r-- | packages/pogen/src/pogen.ts | 48 | ||||
-rw-r--r-- | packages/pogen/src/potextract.ts (renamed from packages/pogen/pogen.ts) | 217 | ||||
-rw-r--r-- | packages/pogen/tsconfig.json | 23 |
13 files changed, 413 insertions, 182 deletions
diff --git a/packages/pogen/bin/pogen b/packages/pogen/bin/pogen index a7ef879d8..3b17d1df7 100755 --- a/packages/pogen/bin/pogen +++ b/packages/pogen/bin/pogen @@ -1,2 +1,2 @@ -#!/usr/bin/env node +#!/usr/bin/env -S node --trace-deprecation require('../lib/pogen.js').main(); diff --git a/packages/pogen/example/proj1/package.json b/packages/pogen/example/proj1/package.json index 954139ecf..97adf0f3a 100644 --- a/packages/pogen/example/proj1/package.json +++ b/packages/pogen/example/proj1/package.json @@ -7,5 +7,8 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", - "license": "ISC" + "license": "ISC", + "pogen": { + "domain": "test" + } } diff --git a/packages/pogen/example/messages.po b/packages/pogen/example/proj1/src/i18n/test.pot index 1addae3f2..8bc5ef236 100644 --- a/packages/pogen/example/messages.po +++ b/packages/pogen/example/proj1/src/i18n/test.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-01-27 01:51+0100\n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,68 +17,78 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: example/test.ts:3 -#, csharp-format +#: src/test.ts:4 +#, c-format msgid "Hello1, World" msgstr "" -#: example/test.ts:4 -#, csharp-format -msgid "Hello2, World" +#: src/test.ts:8 +#, c-format +msgid "Hello, quoted \"world\"" msgstr "" -#: example/test.ts:5 -#, csharp-format -msgid "Hello3, World" -msgstr "" - -#. This is a comment and should be included -#: example/test.ts:9 -#, csharp-format -msgid "Hello4, World" -msgstr "" - -#: example/test.ts:12 -#, csharp-format +#: src/test.ts:15 +#, c-format msgid "Hello5, World" msgstr "" -#: example/test.ts:13 -#, csharp-format -msgid "Hello6,{0} World" +#: src/test.ts:16 +#, c-format +msgid "Hello6,%1$s World" msgstr "" #. This one has a multi line comment. #. It has multiple lines, and a trailing empty line. #. -#: example/test.ts:20 -#, csharp-format -msgid "Hello7,{0} World{1}" +#: src/test.ts:23 +#, c-format +msgid "Hello7,%1$s World%2$s" msgstr "" -#: example/test.ts:21 -#, csharp-format -msgid "{0}Hello8,{1} World{2}" +#: src/test.ts:23 +#, c-format +msgid "one %1$s" +msgid_plural "many %1$s" +msgstr[0] "" +msgstr[1] "" + +#: src/test.ts:26 +#, c-format +msgid "one bla %1$s" +msgid_plural "many bla %1$s" +msgstr[0] "" +msgstr[1] "" + +#: src/test.ts:31 +#, c-format +msgid "I have %1$s apple" +msgid_plural "I have %1$s apples" +msgstr[0] "" +msgstr[1] "" + +#: src/test.ts:35 +#, c-format +msgid "%1$sHello8,%2$s World%3$s" msgstr "" #. #. This one has a multi line comment. #. It has multiple lines, and a leading empty line. -#: example/test.ts:28 -#, csharp-format +#: src/test.ts:42 +#, c-format msgid "Hello9,\" '\" World" msgstr "" -#: example/test.ts:32 -#, csharp-format +#: src/test.ts:46 +#, c-format msgid "" "Hello10\n" " ,\" '\" Wo\n" " rld" msgstr "" -#: example/test.ts:37 -#, csharp-format +#: src/test.ts:51 +#, c-format msgid "" "Hello11 this is a long long string\n" "it will go over multiple lines and in the pofile\n" @@ -86,8 +96,8 @@ msgid "" msgstr "" #. This is a single line comment -#: example/test.ts:42 -#, csharp-format +#: src/test.ts:56 +#, c-format msgid "" "Hello12 this is a long long string it will go over multiple lines and in the " "pofile it should be wrapped and stuff. asdf asdf asdf asdf asdf asdf asdf asdf " @@ -95,13 +105,26 @@ msgid "" "asdf" msgstr "" -#: example/test.ts:42 -#, csharp-format +#. First occurrence +#: src/test.ts:65 +#, c-format msgid "This message appears twice" msgstr "" -#: example/test.ts:45 -#, csharp-format -msgid "This message appears twice" +#: src/test2.tsx:1 +#, c-format +msgid "foo %1$s foo baz" +msgstr "" + +#: src/test2.tsx:5 +#, c-format +msgid "singular form second line" +msgid_plural "plural form" +msgstr[0] "" +msgstr[1] "" + +#: src/test2.tsx:17 +#, c-format +msgid "\"foo\"" msgstr "" diff --git a/packages/pogen/example/test.ts b/packages/pogen/example/proj1/src/test.ts index 6577fa314..2e9b4cbdd 100644 --- a/packages/pogen/example/test.ts +++ b/packages/pogen/example/proj1/src/test.ts @@ -1,9 +1,12 @@ declare var i18n: any; + console.log(i18n`Hello1, World`); console.log(i18n.foo()`Hello2, World`); console.log(i18n.foo()`Hello3, World`); +console.log(i18n`Hello, quoted "world"`); + /* This is a comment and should be included */ console.log(i18n().foo()`Hello4, World`); diff --git a/packages/pogen/example/test2.tsx b/packages/pogen/example/proj1/src/test2.tsx index 4133f86fb..1c1ab49f2 100644 --- a/packages/pogen/example/test2.tsx +++ b/packages/pogen/example/proj1/src/test2.tsx @@ -13,3 +13,5 @@ let y = ( </i18n.TranslatePlural> </i18n.TranslateSwitch> ); + +let z = <i18n.Translate>"foo"</i18n.Translate>; diff --git a/packages/pogen/example/proj1/tsconfig.json b/packages/pogen/example/proj1/tsconfig.json index 30cb65e1d..36ef053db 100644 --- a/packages/pogen/example/proj1/tsconfig.json +++ b/packages/pogen/example/proj1/tsconfig.json @@ -4,7 +4,7 @@ "composite": true, "declaration": true, "declarationMap": false, - "target": "ES6", + "target": "ES2020", "module": "ESNext", "moduleResolution": "node", "sourceMap": true, diff --git a/packages/pogen/package.json b/packages/pogen/package.json index 3d744f736..24edc348b 100644 --- a/packages/pogen/package.json +++ b/packages/pogen/package.json @@ -1,19 +1,21 @@ { "name": "@gnu-taler/pogen", - "version": "0.0.5", + "version": "0.10.7", "bin": { "pogen": "bin/pogen" }, "author": "Florian Dold", "license": "GPL-2.0+", "scripts": { - "prepare": "tsc", + "clean": "rm -rf lib", "compile": "tsc" }, "devDependencies": { - "typescript": "^4.1.3" + "po2json": "^0.4.5", + "typescript": "^5.3.3" }, "dependencies": { - "@types/node": "^14.14.22" + "@types/node": "^18.11.17", + "glob": "^10.3.10" } } diff --git a/packages/pogen/po2.js b/packages/pogen/po2.js deleted file mode 100644 index 532a1522f..000000000 --- a/packages/pogen/po2.js +++ /dev/null @@ -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));
\ No newline at end of file diff --git a/packages/pogen/dumpTree.ts b/packages/pogen/src/dumpTree.ts index af25caf32..af25caf32 100644 --- a/packages/pogen/dumpTree.ts +++ b/packages/pogen/src/dumpTree.ts diff --git a/packages/pogen/src/po2ts.ts b/packages/pogen/src/po2ts.ts new file mode 100644 index 000000000..0b5b1384d --- /dev/null +++ b/packages/pogen/src/po2ts.ts @@ -0,0 +1,146 @@ +/* + 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 po2jsonLib from "po2json"; +import * as fs from "fs"; +import glob = require("glob"); + +//types defined by the po2json library +type Header = { + domain: string; + lang: string; + 'plural_forms': string; +}; + +type MessagesType = Record<string, undefined | Array<string>> & { "": Header } +interface pojsonType { + // X-Domain or 'messages' + domain: string; + locale_data: { + messages: MessagesType + } +} +// ----------- end pf po2json + +interface StringsType { + // X-Domain or 'messages' + domain: string; + lang: string; + completeness: number, + 'plural_forms': string; + locale_data: { + messages: Record<string, undefined | Array<string>> + } +} + +// This prelude match the types above +const TYPES_FOR_STRING_PRELUDE = ` +export interface StringsType { + domain: string; + lang: string; + completeness: number; + 'plural_forms': string; + locale_data: { + messages: Record<string, unknown>; + }; +}; +`; + +const DEFAULT_STRING_PRELUDE = `${TYPES_FOR_STRING_PRELUDE}export const strings: Record<string,StringsType> = {};\n\n` + + +export function po2ts(): void { + const files = glob.sync("src/i18n/*.po"); + + if (files.length === 0) { + console.error("no .po files found in src/i18n/"); + process.exit(1); + } + + console.log(files); + + let prelude: string; + try { + prelude = fs.readFileSync("src/i18n/strings-prelude", "utf-8") + } catch (e) { + prelude = DEFAULT_STRING_PRELUDE + } + + const chunks = [prelude]; + + 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 poAsJson: pojsonType = po2jsonLib.parseFileSync(filename, { + format: "jed1.x", + fuzzy: true, + }); + const header = poAsJson.locale_data.messages[""] + const total = calculateTotalTranslations(poAsJson.locale_data.messages) + const completeness = + header.lang === "en" + ? 100 // 'en' is always complete + : Math.floor(total.translations * 100 / total.keys); + + const strings: StringsType = { + locale_data: poAsJson.locale_data, + domain: poAsJson.domain, + plural_forms: header.plural_forms, + lang: header.lang, + completeness, + } + const value = JSON.stringify(strings, undefined, 2) + const s = `strings['${lang}'] = ${value};\n\n` + chunks.push(s); + } + + const tsContents = chunks.join(""); + + fs.writeFileSync("src/i18n/strings.ts", tsContents); +} + +function calculateTotalTranslations(msgs: MessagesType): { keys: number, translations: number } { + const kv = Object.entries(msgs) + const [keys, translations] = kv.reduce(([total, withTranslation], translation) => { + if (!translation || translation.length !== 2 || !translation[1]) { + //current key is empty + return [total, withTranslation] + } + const v = translation[1] + if (!Array.isArray(v)) { + // this is not a translation + return [total, withTranslation] + } + if (!v.length || !v[0].length) { + //translation is missing + return [total + 1, withTranslation] + } + //current key has a translation + return [total + 1, withTranslation + 1] + }, [0, 0]) + return { keys, translations } +}
\ No newline at end of file diff --git a/packages/pogen/src/pogen.ts b/packages/pogen/src/pogen.ts new file mode 100644 index 000000000..72b7c81d7 --- /dev/null +++ b/packages/pogen/src/pogen.ts @@ -0,0 +1,48 @@ +import { potextract } from "./potextract.js"; +import * as child_process from "child_process"; +import * as fs from "fs"; +import glob = require("glob"); +import { po2ts } from "./po2ts.js"; + +function usage(): never { + console.log("usage: pogen <extract|merge|emit>"); + process.exit(1); +} + +export function main() { + const subcommand = process.argv[2]; + if (process.argv.includes("--help") || !subcommand) { + usage(); + } + switch (subcommand) { + case "extract": + potextract(); + break; + case "merge": { + const packageJson = JSON.parse( + fs.readFileSync("./package.json", { encoding: "utf-8" }), + ); + + const poDomain = packageJson.pogen?.domain; + if (!poDomain) { + console.error("missing 'pogen.domain' field in package.json"); + process.exit(1); + } + const files = glob.sync("src/i18n/*.po"); + console.log(files); + for (const f of files) { + console.log(`merging ${f}`); + child_process.execSync( + `msgmerge -o '${f}' '${f}' 'src/i18n/${poDomain}.pot'`, + ); + } + break; + } + case "emit": + po2ts(); + break; + default: + console.error(`unknown subcommand '${subcommand}'`); + usage(); + } +} diff --git a/packages/pogen/pogen.ts b/packages/pogen/src/potextract.ts index 23ac389f4..243d44c6f 100644 --- a/packages/pogen/pogen.ts +++ b/packages/pogen/src/potextract.ts @@ -1,43 +1,59 @@ /* - This file is part of TALER - (C) 2016 GNUnet e.V. + This file is part of GNU Taler + (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 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 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 - 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 + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ /** * Imports. */ -import { readFileSync } from "fs"; import * as ts from "typescript"; +import * as fs from "fs"; +import * as path from "path" + +const DEFAULT_PO_HEADER = `# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\\n" +"Report-Msgid-Bugs-To: \\n" +"POT-Creation-Date: 2016-11-23 00:00+0100\\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" +"Language-Team: LANGUAGE <LL@li.org>\\n" +"Language: \\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=UTF-8\\n" +"Content-Transfer-Encoding: 8bit\\n"\n\n` + function wordwrap(str: string, width: number = 80): string[] { var regex = ".{1," + width + "}(\\s|$)|\\S+(\\s|$)"; return str.match(RegExp(regex, "g")); } -export function processFile(sourceFile: ts.SourceFile) { - processNode(sourceFile); +function processFile( + sourceFile: ts.SourceFile, + outChunks: string[], + knownMessageIds: Set<string>, +) { let lastTokLine = 0; let preLastTokLine = 0; + processNode(sourceFile); function getTemplate(node: ts.Node): string { switch (node.kind) { @@ -138,7 +154,7 @@ export function processFile(sourceFile: ts.SourceFile) { path, line: lc.line, comment: getComment(tte), - template: getTemplate(tte.template).replace(/"/g, '\\"'), + template: getTemplate(tte.template), }; return res; } @@ -146,26 +162,29 @@ export function processFile(sourceFile: ts.SourceFile) { function formatMsgComment(line: number, comment?: string) { if (comment) { for (let cl of comment.split("\n")) { - console.log(`#. ${cl}`); + outChunks.push(`#. ${cl}\n`); } } - console.log(`#: ${sourceFile.fileName}:${line + 1}`); - console.log(`#, c-format`); + const fn = path.posix.relative(process.cwd(), sourceFile.fileName); + outChunks.push(`#: ${fn}:${line + 1}\n`); + outChunks.push(`#, c-format\n`); } function formatMsgLine(head: string, msg: string) { + const m = msg.match(/(.*\n|.+$)/g) + if (!m) return; // Do escaping, wrap break at newlines - let parts = msg - .match(/(.*\n|.+$)/g) - .map((x) => x.replace(/\n/g, "\\n")) + console.log("head", JSON.stringify(head)); + console.log("msg", JSON.stringify(msg)); + let parts = m.map((x) => x.replace(/\n/g, "\\n").replace(/"/g, '\\"')) .map((p) => wordwrap(p)) .reduce((a, b) => a.concat(b)); if (parts.length == 1) { - console.log(`${head} "${parts[0]}"`); + outChunks.push(`${head} "${parts[0]}"\n`); } else { - console.log(`${head} ""`); + outChunks.push(`${head} ""\n`); for (let p of parts) { - console.log(`"${p}"`); + outChunks.push(`"${p}"\n`); } } } @@ -197,7 +216,7 @@ export function processFile(sourceFile: ts.SourceFile) { } } - function trim(s) { + function trim(s: string) { return s.replace(/^[ \n\t]*/, "").replace(/[ \n\t]*$/, ""); } @@ -208,7 +227,7 @@ export function processFile(sourceFile: ts.SourceFile) { switch (childNode.kind) { case ts.SyntaxKind.JsxText: { let e = childNode as ts.JsxText; - let s = e.getFullText(); + let s = e.text; let t = s.split("\n").map(trim).join(" "); if (s[0] === " ") { t = " " + t; @@ -220,6 +239,7 @@ export function processFile(sourceFile: ts.SourceFile) { } case ts.SyntaxKind.JsxOpeningElement: break; + case ts.SyntaxKind.JsxSelfClosingElement: case ts.SyntaxKind.JsxElement: fragments.push(`%${holeNum[0]++}$s`); break; @@ -231,16 +251,13 @@ export function processFile(sourceFile: ts.SourceFile) { case ts.SyntaxKind.JsxClosingElement: break; default: + console.log("unhandled node type: ", childNode.kind) let lc = ts.getLineAndCharacterOfPosition( childNode.getSourceFile(), childNode.getStart(), ); console.error( - `unrecognized syntax in JSX Element ${ - ts.SyntaxKind[childNode.kind] - } (${childNode.getSourceFile().fileName}:${lc.line + 1}:${ - lc.character + 1 - }`, + `unrecognized syntax in JSX Element ${ts.SyntaxKind[childNode.kind]} (${childNode.getSourceFile().fileName}:${lc.line + 1}:${lc.character + 1}`, ); break; } @@ -293,10 +310,13 @@ export function processFile(sourceFile: ts.SourceFile) { let content = getJsxContent(node); let { line } = ts.getLineAndCharacterOfPosition(sourceFile, node.pos); let comment = getComment(node); - formatMsgComment(line, comment); - formatMsgLine("msgid", content); - console.log(`msgstr ""`); - console.log(); + if (!knownMessageIds.has(content)) { + knownMessageIds.add(content); + formatMsgComment(line, comment); + formatMsgLine("msgid", content); + outChunks.push(`msgstr ""\n`); + outChunks.push("\n"); + } return; } if (arrayEq(path, ["i18n", "TranslateSwitch"])) { @@ -313,11 +333,14 @@ export function processFile(sourceFile: ts.SourceFile) { console.error("plural form missing"); process.exit(1); } - formatMsgLine("msgid", singularForm); - formatMsgLine("msgid_plural", pluralForm); - console.log(`msgstr[0] ""`); - console.log(`msgstr[1] ""`); - console.log(); + if (!knownMessageIds.has(singularForm)) { + knownMessageIds.add(singularForm); + formatMsgLine("msgid", singularForm); + formatMsgLine("msgid_plural", pluralForm); + outChunks.push(`msgstr[0] ""\n`); + outChunks.push(`msgstr[1] ""\n`); + outChunks.push(`\n`); + } return; } break; @@ -342,29 +365,35 @@ export function processFile(sourceFile: ts.SourceFile) { <ts.TaggedTemplateExpression>ce.arguments[1], ); let comment = getComment(ce); - - formatMsgComment(line, comment); - formatMsgLine("msgid", t1.template); - formatMsgLine("msgid_plural", t2.template); - console.log(`msgstr[0] ""`); - console.log(`msgstr[1] ""`); - console.log(); + const msgid = t1.template; + if (!knownMessageIds.has(msgid)) { + knownMessageIds.add(msgid); + formatMsgComment(line, comment); + formatMsgLine("msgid", t1.template); + formatMsgLine("msgid_plural", t2.template); + outChunks.push(`msgstr[0] ""\n`); + outChunks.push(`msgstr[1] ""\n`); + outChunks.push("\n"); + } // Important: no processing for child i18n expressions here return; } case ts.SyntaxKind.TaggedTemplateExpression: { let tte = <ts.TaggedTemplateExpression>node; - let { comment, template, line, path } = processTaggedTemplateExpression( - tte, - ); + let { comment, template, line, path } = + processTaggedTemplateExpression(tte); if (path[0] != "i18n") { break; } - formatMsgComment(line, comment); - formatMsgLine("msgid", template); - console.log(`msgstr ""`); - console.log(); + const msgid = template; + if (!knownMessageIds.has(msgid)) { + knownMessageIds.add(msgid); + formatMsgComment(line, comment); + formatMsgLine("msgid", template); + outChunks.push(`msgstr ""\n`); + outChunks.push("\n"); + } break; } } @@ -373,7 +402,7 @@ export function processFile(sourceFile: ts.SourceFile) { } } -export function main() { +export function potextract() { const configPath = ts.findConfigFile( /*searchPath*/ "./", ts.sys.fileExists, @@ -396,41 +425,47 @@ export function main() { }, ); - const fileNames = cmdline.fileNames; + const prog = ts.createProgram({ + options: cmdline.options, + rootNames: cmdline.fileNames, + }); - fileNames.sort(); + const allFiles = prog.getSourceFiles(); - const outChunks: string[] = []; + const ownFiles = allFiles.filter( + (x) => + !x.isDeclarationFile && + !prog.isSourceFileFromExternalLibrary(x) && + !prog.isSourceFileDefaultLibrary(x), + ); - outChunks.push(`# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\\n" -"Report-Msgid-Bugs-To: \\n" -"POT-Creation-Date: 2016-11-23 00:00+0100\\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" -"Language-Team: LANGUAGE <LL@li.org>\\n" -"Language: \\n" -"MIME-Version: 1.0\\n" -"Content-Type: text/plain; charset=UTF-8\\n" -"Content-Transfer-Encoding: 8bit\\n"`); - - fileNames.forEach((fileName) => { - let sourceFile = ts.createSourceFile( - fileName, - readFileSync(fileName).toString(), - ts.ScriptTarget.ES2016, - /*setParentNodes */ true, - ); - processFile(sourceFile); - }); + let header: string + try { + header = fs.readFileSync("src/i18n/poheader", "utf-8") + } catch (e) { + header = DEFAULT_PO_HEADER + } + + const chunks = [header]; + + const knownMessageIds = new Set<string>(); - const out = outChunks.join(""); - console.log(out); + for (const f of ownFiles) { + processFile(f, chunks, knownMessageIds); + } + + const pot = chunks.join(""); + + //console.log(pot); + + const packageJson = JSON.parse( + fs.readFileSync("./package.json", { encoding: "utf-8" }), + ); + + const poDomain = packageJson.pogen?.domain; + if (!poDomain) { + console.error("missing 'pogen.domain' field in package.json"); + process.exit(1); + } + fs.writeFileSync(`./src/i18n/${poDomain}.pot`, pot); } diff --git a/packages/pogen/tsconfig.json b/packages/pogen/tsconfig.json index d61e5595a..482ce6fe8 100644 --- a/packages/pogen/tsconfig.json +++ b/packages/pogen/tsconfig.json @@ -1,13 +1,14 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "outDir": "lib", - "incremental": true - }, - "files": [ - "pogen.ts" - ] + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "noImplicitAny": false, + "outDir": "lib", + "incremental": true, + "moduleResolution": "node", + "sourceMap": true, + "lib": ["ES2020"], + "types": ["node"] + }, + "include": ["src/**/*.ts"] } |