From a09330268e0f49628ee02166118ed3faa8920d1a Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:21:10 +0200 Subject: [PATCH 1/7] renaming printMakePotModuleInfo --- src/jsonCommand.ts | 4 ++-- src/parser/exec.ts | 42 ++++++++++-------------------------------- src/potCommand.ts | 4 ++-- src/utils/common.ts | 4 ++-- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/src/jsonCommand.ts b/src/jsonCommand.ts index 8d5cbd5..4114a8b 100644 --- a/src/jsonCommand.ts +++ b/src/jsonCommand.ts @@ -1,12 +1,12 @@ import MakeJsonCommand from "./parser/makeJson.js"; import type { MakeJsonArgs } from "./types.js"; -import { printMakePotModuleInfo, printTimeElapsed } from "./utils/common.js"; +import { printModuleInfo, printTimeElapsed } from "./utils/common.js"; export default function makeJsonCommand(args: MakeJsonArgs) { const makeJson = new MakeJsonCommand(args); if (Object.keys(args).length > 0) { - printMakePotModuleInfo(); + printModuleInfo(); /* capture the start time */ const timeStart = new Date(); makeJson diff --git a/src/parser/exec.ts b/src/parser/exec.ts index 7de31d2..9454bbf 100644 --- a/src/parser/exec.ts +++ b/src/parser/exec.ts @@ -3,25 +3,15 @@ import type { SingleBar } from "cli-progress"; import { type GetTextTranslations, po } from "gettext-parser"; import { audit } from "../extractors/auditStrings.js"; import { generateHeader, translationsHeaders } from "../extractors/headers.js"; -import { getCharset, getEncodingCharset } from "../fs/fs"; -import type { Args, Patterns } from "../types.js"; -import { getCopyright, printStats } from "../utils/common.js"; +import { getCharset, getEncodingCharset } from "../fs/fs.js"; +import type { Args } from "../types.js"; +import { getCopyright, outputPathRecap, printStats } from "../utils/common.js"; +import { outputJson } from "../utils/output"; import { getPatterns } from "./patterns.js"; import { processFiles } from "./process.js"; import { initProgress } from "./progress.js"; import { taskRunner } from "./taskRunner.js"; -/** - * Returns the output path recap - * - * @param {string} cwd - The current working directory - * @param {Patterns} patterns - The patterns to be used for the extraction process - * @return {string} - The output path recap - */ -function outputPathRecap(cwd: string, patterns: Patterns): string { - return `\nScript Path: ${cwd}\nfor ${patterns.include.join()}\nignoring patterns: ${patterns.exclude.join()}\n`; -} - /** * Runs the parser and generates the pot file or the json file based on the command line arguments * @@ -47,7 +37,6 @@ export async function exec(args: Args): Promise { * The progress bar that is used to show the progress of the extraction process. */ const progressBar: SingleBar = initProgress(args, 0); - progressBar.start(3, 1, { filename: `Resolving files in ${path.resolve(args.paths.cwd)}`, }); @@ -59,7 +48,7 @@ export async function exec(args: Args): Promise { const files = await processFiles(patterns, args); progressBar.update(2, { - filename: `Found ${files.length} files`, + filename: `Found ${files.length} files... `, }); translationsUnion = await taskRunner( @@ -80,37 +69,26 @@ export async function exec(args: Args): Promise { /** generate the json file based on the --json flag passed */ if (args.options?.json) { - // generate the json file - const jedData: { - [p: string]: { [p: string]: [string, string] }; - } = { - [args.slug]: { - "": potHeader, - ...(translationsUnion.toJson() as { [p: string]: [string, string] }), - }, - }; - const i18n = new Tannin(jedData); - - return i18n.toString(); + return outputJson(args, potHeader, translationsUnion); } - // generate the pot file json + /** Generate the pot file json */ const getTextTranslations: GetTextTranslations = { charset: getEncodingCharset(args.options?.charset), headers: potHeader as { [headerName: string]: string }, translations: translationsUnion.toJson(), }; - // And then compile the pot file to a string + /** And then compile the pot file to a string */ const pluginTranslations = po .compile(getTextTranslations) .toString(getCharset(args.options?.charset)); - // return the pot file as a string, prefixed with the header + /** Return the pot file as a string, prefixed with the header */ const copyrightComment = args.options?.fileComment || getCopyright( - args.slug, + args.headers?.name || args.slug, (args.headers?.license as string) ?? "GPL v2 or later", ); return `${copyrightComment}\n${pluginTranslations}`; diff --git a/src/potCommand.ts b/src/potCommand.ts index 1cabaa2..20234fa 100644 --- a/src/potCommand.ts +++ b/src/potCommand.ts @@ -1,11 +1,11 @@ import { makePot } from "./parser/makePot.js"; import type { Args } from "./types.js"; -import { printMakePotModuleInfo, printTimeElapsed } from "./utils/common.js"; +import { printModuleInfo, printTimeElapsed } from "./utils/common.js"; export default function potCommand(args: Args) { if (Object.keys(args).length > 0) { - printMakePotModuleInfo(); + printModuleInfo(); /* capture the start time */ const timeStart = new Date(); /** make the pot file */ diff --git a/src/utils/common.ts b/src/utils/common.ts index d93a32a..6cef5f1 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -132,7 +132,7 @@ export function getPkgJsonData( /** * Print the module header with the current version and name */ -export function printMakePotModuleInfo() { +export function printModuleInfo() { const { version, name } = getPkgJsonData(modulePath, "name", "version"); /* print the version */ console.log(`${name} version: ${version}`); @@ -150,7 +150,7 @@ export function printTimeElapsed( timeEnd: Date = new Date(), ) { console.log( - `\nšŸš€ ${scriptName}: Job completed! ${scriptName.split("-")[1]} file created in ${ + `\nšŸš€ ${scriptName}: Task completed! ${scriptName.split("-")[1]} file created in ${ timeEnd.getTime() - timeStart.getTime() }ms`, ); From a4cfc99275c3e03b057bab6ee99064c5d8b2432a Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:22:27 +0200 Subject: [PATCH 2/7] outputJson fn --- src/utils/output.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/utils/output.ts diff --git a/src/utils/output.ts b/src/utils/output.ts new file mode 100644 index 0000000..1fa2f1f --- /dev/null +++ b/src/utils/output.ts @@ -0,0 +1,29 @@ +import type { SetOfBlocks } from "gettext-merger"; +import Tannin from "tannin"; +import type { Args } from "../types"; + +/** + * Outputs the pot file in json format based on the command line arguments --json option + * + * @param {Args} args - The command line arguments + * @param {Record} potHeader - The pot file header + * @param {SetOfBlocks} translationsUnion - The translations union + * @return {string} - The output pot file + */ +export function outputJson( + args: Args, + potHeader: Record | null, + translationsUnion: SetOfBlocks, +) { + const jedData: { + [p: string]: { [p: string]: [string, string] }; + } = { + [args.slug]: { + "": potHeader ?? {}, + ...(translationsUnion.toJson() as { [p: string]: [string, string] }), + }, + }; + const i18n = new Tannin(jedData); + + return i18n.toString(); +} From 493f277e738c023a24dbcb947e29bccb00ed5214 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:23:17 +0200 Subject: [PATCH 3/7] moved outputPathRecap function --- src/utils/common.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/utils/common.ts b/src/utils/common.ts index 6cef5f1..bea7ef5 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -2,6 +2,7 @@ import fs from "node:fs"; import { cpus, totalmem } from "node:os"; import path from "node:path"; import { modulePath } from "../const.js"; +import type { Patterns } from "../types"; /** * A function that removes comment markup from a given string. @@ -175,3 +176,14 @@ export function printStats() { "cores", ); } + +/** + * Returns the output path recap + * + * @param {string} cwd - The current working directory + * @param {Patterns} patterns - The patterns to be used for the extraction process + * @return {string} - The output path recap + */ +export function outputPathRecap(cwd: string, patterns: Patterns): string { + return `\nScript Path: ${cwd}\nfor ${patterns.include.join()}\nignoring patterns: ${patterns.exclude.join()}\n`; +} From 553f45a7eb65381218dea7849f7007d13aefde47 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:24:24 +0200 Subject: [PATCH 4/7] updated comments / cli strings --- src/extractors/css.ts | 2 +- src/fs/fs.ts | 2 +- src/parser/makeJson.ts | 26 ++++++++++++++++++++------ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/extractors/css.ts b/src/extractors/css.ts index 22c124e..1b56611 100644 --- a/src/extractors/css.ts +++ b/src/extractors/css.ts @@ -24,7 +24,7 @@ export function extractCssThemeData( fileData = extractFileData(commentBlock); if ("Theme Name" in fileData) { - console.log(`šŸ”µ Theme stylesheet detected. ${styleCssFile}`); + console.log(`šŸ”µ Theme stylesheet detected. (${styleCssFile})`); args.domain = "theme"; const themeInfo: Record = {}; diff --git a/src/fs/fs.ts b/src/fs/fs.ts index 11d4b71..d4328a4 100644 --- a/src/fs/fs.ts +++ b/src/fs/fs.ts @@ -101,7 +101,7 @@ export function writeFile(fileContent: string, args: Args): void { if (ensureFolderExists(path.dirname(dest))) { // get the encoding charset const encodingCharset = getCharset(args.options?.charset); - console.log(`\nFile created at ${dest}`); + console.log(`\nPot File created at ${dest}`); // write the file const potBuffer = Buffer.from(fileContent); diff --git a/src/parser/makeJson.ts b/src/parser/makeJson.ts index 545c0ca..69982cb 100644 --- a/src/parser/makeJson.ts +++ b/src/parser/makeJson.ts @@ -121,11 +121,23 @@ export class MakeJsonCommand { if (typeof this.scriptName === "string") { const pot = this.addPot(file, this.scriptName); - output[pot.filename] = pot.data; + if (pot.data) { + output[pot.filename] = pot.data; + } else { + console.log( + `āŒ Translation strings not found in Script ${this.scriptName} in ${file} po file`, + ); + } } else if (Array.isArray(this.scriptName)) { for (const script of this.scriptName) { const pot = this.addPot(file, script); - output[pot.filename] = pot.data; + if (pot.data) { + output[pot.filename] = pot.data; + } else { + console.log( + `āŒ Translation strings not found in Script ${script} in ${file} po file`, + ); + } } } } @@ -160,7 +172,9 @@ export class MakeJsonCommand { const destinationPath = path.join(this.destination, filename); fs.writeFileSync(destinationPath, contentString); - console.log(`JSON file written to ${destinationPath} with ${filename}`); + console.log( + `āœ… JSON file written to ${destinationPath} with ${filename}`, + ); } // return the output @@ -428,10 +442,10 @@ export class MakeJsonCommand { } } - // check if the po file is empty + // check if the po file is empty, 1 means that the header is the only string available // TODO: if the json file is empty, we should delete it? - if (Object.keys(filteredPo.translations[""][""]).length === 0) { - console.log("The po file has no translations strings used in the script"); + if (Object.keys(filteredPo.translations[""]).length <= 1) { + return null; } return filteredPo; From 90010f247aeea0e8e0687ab8e382a3fa194fa74c Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:25:14 +0200 Subject: [PATCH 5/7] a better way to display the file count --- src/parser/process.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/parser/process.ts b/src/parser/process.ts index aab0f3a..2d9994d 100644 --- a/src/parser/process.ts +++ b/src/parser/process.ts @@ -22,13 +22,20 @@ export async function processFiles( progressBar?: SingleBar, ): Promise[]> { const tasks: Promise[] = []; - let filesCount = 0; + let processedFilesCount = 0; const files = getFiles(args, patterns); + if (progressBar) { + progressBar.setTotal(Object.values(files).length); + progressBar.update(0, { + filename: `Found ${Object.values(files).length} files`, + }); + } + // loop through the files and parse them for await (const file of files) { - filesCount++; + processedFilesCount++; const filename = path.basename(file); const ext = path.extname(file).replace(/^./, ""); const fileRealPath = path.resolve(args.paths.cwd, file); @@ -46,8 +53,7 @@ export async function processFiles( } if (progressBar) { - progressBar.update(filesCount, { filename: filename }); - progressBar.setTotal(Object.values(files).length); + progressBar.update(processedFilesCount, { filename: filename }); progressBar.render(); } } From e11e584642b946c08c534b09a6e4ee9c8e0cdf88 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:25:52 +0200 Subject: [PATCH 6/7] allows to find js files into build subfolders (makejson) --- src/parser/makeJson.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/makeJson.ts b/src/parser/makeJson.ts index 69982cb..a5a0005 100644 --- a/src/parser/makeJson.ts +++ b/src/parser/makeJson.ts @@ -110,7 +110,7 @@ export class MakeJsonCommand { const output: Record = {}; for (const file of files) { if (!this.scriptName) { - this.scriptName = await glob("*.js", { + this.scriptName = await glob("**/*.js", { cwd: this.source, nodir: true, }); From 73945c1333f1f2b8bbb98e217dcf4f5a8afe6d6b Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sun, 18 May 2025 18:25:58 +0200 Subject: [PATCH 7/7] chore --- src/parser/makeJson.ts | 59 ++++++++++++------------------------------ 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/src/parser/makeJson.ts b/src/parser/makeJson.ts index a5a0005..9bbc675 100644 --- a/src/parser/makeJson.ts +++ b/src/parser/makeJson.ts @@ -191,7 +191,7 @@ export class MakeJsonCommand { file: string, script: string, encoding: BufferEncoding = "utf8", - ): MakeJson { + ): MakeJson | null { // Get the file path const filePath = path.join(this.destination, file); @@ -205,11 +205,11 @@ export class MakeJsonCommand { // get the strings used in the script const scriptContent = this.parseScript(script); - // compare the strings used in the script with the strings in the po file - const stringsNotInPoFile = this.compareStrings( - scriptContent.blocks, - poContent, - ); + // compare the strings used in the script with the strings in the po file + const stringsNotInPoFile = this.compareStrings( + scriptContent.blocks, + poContent, + ); if (!stringsNotInPoFile) { return null; @@ -328,47 +328,20 @@ export class MakeJsonCommand { } /** - * Takes the header content and extracts the plural forms. - * @param headerContent - The header content to extract the plural forms from. + * Takes a string and returns its md5 hash. + * @param text * @private - * - * @returns The plural forms extracted from the header. Defaults to 'nplurals=2; plural=(n != 1);' if not found */ - private getPluralForms(headerContent: string): string { - const match = headerContent.match(/Plural-Forms:\s*(.*?)\n/); - return match ? match[1] : "nplurals=2; plural=(n != 1);"; - } - - /** - * Takes the header content and extracts the language. - * @param headerContent - The header content to extract the language from. - * @private - * - * @returns The language code extracted from the header. - */ - private getLanguage(headerContent: string): string { - const match = headerContent.match(/Language:\s*(.*?)\n/); - return match ? match[1] : defaultLocale; + private md5(text: string): string { + return crypto.createHash("md5").update(text).digest("hex"); } /** - * Checks if the given files are compatible with the allowed formats. - * @param files The files array to check. + * Generates the filename for the json file. + * @param script + * @param file * @private - * - * @returns True if the files are compatible, false otherwise. */ - private isCompatibleFile(files: string[]): boolean { - if (!this.allowedFormats) return true; - return files.some((file) => - this.allowedFormats.some((format) => file.endsWith(format)), - ); - } - - private md5(text: string): string { - return crypto.createHash("md5").update(text).digest("hex"); - } - private generateFilename(script: string, file: string): string { const scriptName = this.md5(script); //build the filename for the json file using the po files @@ -386,7 +359,7 @@ export class MakeJsonCommand { private addPot( potFile: string, script: string, - ): { filename: string; data: MakeJson } { + ): { filename: string; data: MakeJson | null } { const filename = this.generateFilename( path.join(this.source, script).replace(/\\/g, "/"), potFile, @@ -407,13 +380,13 @@ export class MakeJsonCommand { private compareStrings( jsArray: SetOfBlocks["blocks"], poObject: GetTextTranslations, - ) { + ): GetTextTranslations | null { // The copy of the po file with only the strings used in the script const filteredPo = { charset: poObject.charset, headers: { ...poObject.headers }, translations: { "": {} }, - }; + } as GetTextTranslations; // copy the original header if (poObject.translations[""][""]) {