diff options
Diffstat (limited to 'packages/pogen/src/po2ts.ts')
-rw-r--r-- | packages/pogen/src/po2ts.ts | 146 |
1 files changed, 146 insertions, 0 deletions
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 |