Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/extractors/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> = {};
Expand Down
2 changes: 1 addition & 1 deletion src/fs/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/jsonCommand.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
42 changes: 10 additions & 32 deletions src/parser/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -47,7 +37,6 @@ export async function exec(args: Args): Promise<string> {
* 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)}`,
});
Expand All @@ -59,7 +48,7 @@ export async function exec(args: Args): Promise<string> {
const files = await processFiles(patterns, args);

progressBar.update(2, {
filename: `Found ${files.length} files`,
filename: `Found ${files.length} files... `,
});

translationsUnion = await taskRunner(
Expand All @@ -80,37 +69,26 @@ export async function exec(args: Args): Promise<string> {

/** 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}`;
Expand Down
87 changes: 37 additions & 50 deletions src/parser/makeJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class MakeJsonCommand {
const output: Record<string, MakeJson> = {};
for (const file of files) {
if (!this.scriptName) {
this.scriptName = await glob("*.js", {
this.scriptName = await glob("**/*.js", {
cwd: this.source,
nodir: true,
});
Expand All @@ -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`,
);
}
}
}
}
Expand Down Expand Up @@ -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
Expand All @@ -177,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);

Expand All @@ -191,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;
Expand Down Expand Up @@ -314,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.
* @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.
* Takes a string and returns its md5 hash.
* @param text
* @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
Expand All @@ -372,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,
Expand All @@ -393,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[""][""]) {
Expand Down Expand Up @@ -428,10 +415,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;
Expand Down
14 changes: 10 additions & 4 deletions src/parser/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ export async function processFiles(
progressBar?: SingleBar,
): Promise<Promise<SetOfBlocks>[]> {
const tasks: Promise<SetOfBlocks>[] = [];
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);
Expand All @@ -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();
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/potCommand.ts
Original file line number Diff line number Diff line change
@@ -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 */
Expand Down
16 changes: 14 additions & 2 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -132,7 +133,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}`);
Expand All @@ -150,7 +151,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`,
);
Expand All @@ -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`;
}
Loading