mirror of
https://github.com/frappe/books.git
synced 2024-11-09 23:30:56 +00:00
chore: type generateTranslations
- shift csvParser to utils
This commit is contained in:
parent
8ba8d7a284
commit
af0d897020
@ -4,7 +4,7 @@ import {
|
||||
getIndexList,
|
||||
getSnippets,
|
||||
getWhitespaceSanitized,
|
||||
} from '../../scripts/helpers';
|
||||
} from '../../utils/translationHelpers';
|
||||
import { ValueError } from './errors';
|
||||
|
||||
type TranslationArgs = boolean | number | string;
|
||||
@ -35,7 +35,7 @@ class TranslationString {
|
||||
}
|
||||
|
||||
#translate() {
|
||||
let indexFormat = getIndexFormat(this.args[0]);
|
||||
let indexFormat = getIndexFormat(this.args[0] as string);
|
||||
indexFormat = getWhitespaceSanitized(indexFormat);
|
||||
|
||||
const translatedIndexFormat =
|
||||
|
@ -15,7 +15,7 @@
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"script:translate": "node scripts/generateTranslations.js",
|
||||
"script:translate": "ts-node -O '{\"module\":\"commonjs\"}' scripts/generateTranslations.ts",
|
||||
"test": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' mocha --reporter nyan --require ts-node/register --require tsconfig-paths/register ./**/tests/**/*.spec.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -1,25 +1,29 @@
|
||||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
const {
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import {
|
||||
getIndexFormat,
|
||||
getWhitespaceSanitized,
|
||||
wrap,
|
||||
splitCsvLine,
|
||||
} = require('./helpers');
|
||||
wrap,
|
||||
} from '../utils/translationHelpers';
|
||||
|
||||
const translationsFolder = path.resolve(__dirname, '..', 'translations');
|
||||
const PATTERN = /(?<!\w)t`([^`]+)`/g;
|
||||
|
||||
function shouldIgnore(p, ignoreList) {
|
||||
return ignoreList.includes(p.split(path.sep).at(-1));
|
||||
function shouldIgnore(p: string, ignoreList: string[]): boolean {
|
||||
const name = p.split(path.sep).at(-1) ?? '';
|
||||
return ignoreList.includes(name);
|
||||
}
|
||||
|
||||
async function getFileList(root, ignoreList) {
|
||||
const contents = await fs.readdir(root);
|
||||
const files = [];
|
||||
const promises = [];
|
||||
async function getFileList(
|
||||
root: string,
|
||||
ignoreList: string[]
|
||||
): Promise<string[]> {
|
||||
const contents: string[] = await fs.readdir(root);
|
||||
const files: string[] = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (let c of contents) {
|
||||
for (const c of contents) {
|
||||
const absPath = path.resolve(root, c);
|
||||
const isDir = (await fs.stat(absPath)).isDirectory();
|
||||
|
||||
@ -37,12 +41,12 @@ async function getFileList(root, ignoreList) {
|
||||
return files;
|
||||
}
|
||||
|
||||
async function getFileContents(fileList) {
|
||||
const contents = [];
|
||||
const promises = [];
|
||||
for (let file of fileList) {
|
||||
const pr = fs.readFile(file, { encoding: 'utf-8' }).then((c) => {
|
||||
contents.push([file, c]);
|
||||
async function getFileContents(fileList: string[]): Promise<Content[]> {
|
||||
const contents: Content[] = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
for (const fileName of fileList) {
|
||||
const pr = fs.readFile(fileName, { encoding: 'utf-8' }).then((content) => {
|
||||
contents.push({ fileName, content });
|
||||
});
|
||||
promises.push(pr);
|
||||
}
|
||||
@ -50,16 +54,18 @@ async function getFileContents(fileList) {
|
||||
return contents;
|
||||
}
|
||||
|
||||
async function getAllTStringsMap(contents) {
|
||||
const strings = new Map();
|
||||
const promises = [];
|
||||
async function getAllTStringsMap(
|
||||
contents: Content[]
|
||||
): Promise<Map<string, string[]>> {
|
||||
const strings: Map<string, string[]> = new Map();
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
contents.forEach(([f, c]) => {
|
||||
const pr = getTStrings(c).then((ts) => {
|
||||
contents.forEach(({ fileName, content }) => {
|
||||
const pr = getTStrings(content).then((ts) => {
|
||||
if (ts.length === 0) {
|
||||
return;
|
||||
}
|
||||
strings.set(f, ts);
|
||||
strings.set(fileName, ts);
|
||||
});
|
||||
promises.push(pr);
|
||||
});
|
||||
@ -68,24 +74,24 @@ async function getAllTStringsMap(contents) {
|
||||
return strings;
|
||||
}
|
||||
|
||||
function getTStrings(content) {
|
||||
function getTStrings(content: string): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
const tStrings = tStringFinder(content);
|
||||
resolve(tStrings);
|
||||
});
|
||||
}
|
||||
|
||||
function tStringFinder(content) {
|
||||
function tStringFinder(content: string): string[] {
|
||||
return [...content.matchAll(PATTERN)].map(([_, t]) => {
|
||||
t = getIndexFormat(t);
|
||||
return getWhitespaceSanitized(t);
|
||||
});
|
||||
}
|
||||
|
||||
function mapToTStringArray(tMap) {
|
||||
const tSet = new Set();
|
||||
for (let k of tMap.keys()) {
|
||||
tMap.get(k).forEach((s) => tSet.add(s));
|
||||
function mapToTStringArray(tMap: Map<string, string[]>): string[] {
|
||||
const tSet: Set<string> = new Set();
|
||||
for (const k of tMap.keys()) {
|
||||
tMap.get(k)!.forEach((s) => tSet.add(s));
|
||||
}
|
||||
const tArray = [...tSet];
|
||||
return tArray.sort();
|
||||
@ -129,14 +135,14 @@ function getLanguageCode() {
|
||||
return process.argv[i + 1] ?? '';
|
||||
}
|
||||
|
||||
function getTranslationFilePath(languageCode) {
|
||||
function getTranslationFilePath(languageCode: string) {
|
||||
return path.resolve(translationsFolder, `${languageCode}.csv`);
|
||||
}
|
||||
|
||||
async function regenerateTranslation(tArray, path) {
|
||||
async function regenerateTranslation(tArray: string[], path: string) {
|
||||
// Removes old strings, adds new strings
|
||||
const contents = await fs.readFile(path, { encoding: 'utf-8' });
|
||||
const map = new Map();
|
||||
const map: Map<string, string[]> = new Map();
|
||||
|
||||
// Populate map
|
||||
contents
|
||||
@ -162,9 +168,9 @@ async function regenerateTranslation(tArray, path) {
|
||||
console.log(`\tregenerated: ${path}`);
|
||||
}
|
||||
|
||||
async function regenerateTranslations(languageCode, tArray) {
|
||||
async function regenerateTranslations(languageCode: string, tArray: string[]) {
|
||||
// regenerate one file
|
||||
if (languageCode) {
|
||||
if (languageCode.length === 0) {
|
||||
const path = getTranslationFilePath(languageCode);
|
||||
regenerateTranslation(tArray, path);
|
||||
return;
|
||||
@ -180,7 +186,7 @@ async function regenerateTranslations(languageCode, tArray) {
|
||||
);
|
||||
}
|
||||
|
||||
async function writeTranslations(languageCode, tArray) {
|
||||
async function writeTranslations(languageCode: string, tArray: string[]) {
|
||||
const path = getTranslationFilePath(languageCode);
|
||||
try {
|
||||
const stat = await fs.stat(path);
|
||||
@ -194,7 +200,7 @@ async function writeTranslations(languageCode, tArray) {
|
||||
);
|
||||
regenerateTranslations(languageCode, tArray);
|
||||
} catch (err) {
|
||||
if (err.errno !== -2) {
|
||||
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
|
||||
@ -204,6 +210,8 @@ async function writeTranslations(languageCode, tArray) {
|
||||
}
|
||||
}
|
||||
|
||||
type Content = { fileName: string; content: string };
|
||||
|
||||
async function run() {
|
||||
if (printHelp()) {
|
||||
return;
|
||||
@ -214,15 +222,15 @@ async function run() {
|
||||
const languageCode = getLanguageCode();
|
||||
|
||||
console.log();
|
||||
const fileList = await getFileList(root, ignoreList);
|
||||
const contents = await getFileContents(fileList);
|
||||
const tMap = await getAllTStringsMap(contents);
|
||||
const tArray = mapToTStringArray(tMap);
|
||||
const fileList: string[] = await getFileList(root, ignoreList);
|
||||
const contents: Content[] = await getFileContents(fileList);
|
||||
const tMap: Map<string, string[]> = await getAllTStringsMap(contents);
|
||||
const tArray: string[] = mapToTStringArray(tMap);
|
||||
|
||||
try {
|
||||
await fs.stat(translationsFolder);
|
||||
} catch (err) {
|
||||
if (err.errno !== -2) {
|
||||
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { DocValueMap } from 'frappe/core/types';
|
||||
import Doc from 'frappe/model/doc';
|
||||
import { isNameAutoSet } from 'frappe/model/naming';
|
||||
import { FieldType, FieldTypeEnum } from 'schemas/types';
|
||||
import { parseCSV } from './csvParser';
|
||||
import { parseCSV } from '../utils/csvParser';
|
||||
import telemetry from './telemetry/telemetry';
|
||||
import { Noun, Verb } from './telemetry/types';
|
||||
|
||||
@ -426,11 +426,11 @@ export class Importer {
|
||||
}
|
||||
|
||||
handleError(doc: Doc, err: Error, status: Status): Status {
|
||||
const messages = [frappe.t`Could not import ${this.doctype} ${doc.name}.`];
|
||||
const messages = [frappe.t`Could not import ${this.doctype} ${doc.name!}.`];
|
||||
|
||||
const message = err.message;
|
||||
if (message?.includes('UNIQUE constraint failed')) {
|
||||
messages.push(frappe.t`${doc.name} already exists.`);
|
||||
messages.push(frappe.t`${doc.name!} already exists.`);
|
||||
} else if (message) {
|
||||
messages.push(message);
|
||||
}
|
||||
|
@ -23,6 +23,9 @@
|
||||
},
|
||||
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
|
||||
},
|
||||
"ts-node": {
|
||||
"files": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
@ -37,7 +40,10 @@
|
||||
"patches/**/*.js",
|
||||
"reports/**/*.ts",
|
||||
"accounting/**/*.ts",
|
||||
"accounting/**/*.ts"
|
||||
"accounting/**/*.ts",
|
||||
|
||||
"scripts/**/*.ts",
|
||||
"utils/csvParser.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
function getIndexFormat(inp) {
|
||||
export function getIndexFormat(inp: string | string[]) {
|
||||
// converts:
|
||||
// ['This is an ', ,' interpolated ',' string.'] and
|
||||
// 'This is an ${variableA} interpolated ${variableB} string.'
|
||||
// to 'This is an ${0} interpolated ${1} string.'
|
||||
let string, snippets;
|
||||
let string: string | undefined = undefined;
|
||||
let snippets: string[] | undefined = undefined;
|
||||
|
||||
if (typeof inp === 'string') {
|
||||
string = inp;
|
||||
} else if (inp instanceof Array) {
|
||||
@ -13,7 +15,7 @@ function getIndexFormat(inp) {
|
||||
}
|
||||
|
||||
if (snippets === undefined) {
|
||||
snippets = getSnippets(string);
|
||||
snippets = getSnippets(string as string);
|
||||
}
|
||||
|
||||
if (snippets.length === 1) {
|
||||
@ -22,41 +24,45 @@ function getIndexFormat(inp) {
|
||||
|
||||
let str = '';
|
||||
snippets.forEach((s, i) => {
|
||||
if (i === snippets.length - 1) {
|
||||
if (i === snippets!.length - 1) {
|
||||
str += s;
|
||||
return;
|
||||
}
|
||||
str += s + '${' + i + '}';
|
||||
});
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
function getSnippets(string) {
|
||||
export function getSnippets(str: string) {
|
||||
let start = 0;
|
||||
const snippets = [...string.matchAll(/\${[^}]+}/g)].map((m) => {
|
||||
let end = m.index;
|
||||
let snip = string.slice(start, end);
|
||||
const snippets = [...str.matchAll(/\${[^}]+}/g)].map((m) => {
|
||||
const end = m.index;
|
||||
if (end === undefined) {
|
||||
return '';
|
||||
}
|
||||
const snip = str.slice(start, end);
|
||||
start = end + m[0].length;
|
||||
return snip;
|
||||
});
|
||||
|
||||
snippets.push(string.slice(start));
|
||||
snippets.push(str.slice(start));
|
||||
return snippets;
|
||||
}
|
||||
|
||||
function getWhitespaceSanitized(s) {
|
||||
return s.replace(/\s+/g, ' ').trim();
|
||||
export function getWhitespaceSanitized(str: string) {
|
||||
return str.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function getIndexList(s) {
|
||||
return [...s.matchAll(/\${([^}]+)}/g)].map(([_, i]) => parseInt(i));
|
||||
export function getIndexList(str: string) {
|
||||
return [...str.matchAll(/\${([^}]+)}/g)].map(([_, i]) => parseInt(i));
|
||||
}
|
||||
|
||||
function wrap(s) {
|
||||
return '`' + s + '`';
|
||||
export function wrap(str: string) {
|
||||
return '`' + str + '`';
|
||||
}
|
||||
|
||||
function splitCsvLine(line) {
|
||||
export function splitCsvLine(line: string) {
|
||||
let t = true;
|
||||
const chars = [...line];
|
||||
const indices = chars
|
||||
@ -82,12 +88,3 @@ function splitCsvLine(line) {
|
||||
splits.push(line.slice(s).trim());
|
||||
return splits.filter((s) => s !== ',' && s !== '');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getIndexFormat,
|
||||
getWhitespaceSanitized,
|
||||
getSnippets,
|
||||
getIndexList,
|
||||
wrap,
|
||||
splitCsvLine,
|
||||
};
|
Loading…
Reference in New Issue
Block a user