refactor translate

This commit is contained in:
Code 2025-01-28 17:34:56 +01:00
parent 2c1e67f3ad
commit 416566962b
41 changed files with 1007 additions and 981 deletions

View File

@ -1,7 +1,6 @@
export { Logger } from 'tslog';
export { MODULE_NAME } from './constants.js';
export { sanitize } from './_cli.js';
export * from './lib/index.js';
export * from './options.js';
export * from './types.js';
export * from './zod_schema.js';

View File

@ -2,10 +2,9 @@ export { Logger } from 'tslog';
import { createLogger } from '@polymech/log';
export { MODULE_NAME } from './constants.js';
export { sanitize } from './_cli.js';
export * from './lib/index.js';
export * from './options.js';
export * from './types.js';
export * from './zod_schema.js';
export * from './zod_types.js';
export const logger = createLogger('commons');
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLE9BQU8sQ0FBQTtBQUM5QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRTVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ3BDLGNBQWMsZ0JBQWdCLENBQUE7QUFDOUIsY0FBYyxjQUFjLENBQUE7QUFDNUIsY0FBYyxZQUFZLENBQUE7QUFDMUIsY0FBYyxpQkFBaUIsQ0FBQTtBQUMvQixjQUFjLGdCQUFnQixDQUFBO0FBRTlCLE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBTyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUEifQ==
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLE9BQU8sQ0FBQTtBQUM5QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRTVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBRXBDLGNBQWMsY0FBYyxDQUFBO0FBQzVCLGNBQWMsWUFBWSxDQUFBO0FBQzFCLGNBQWMsaUJBQWlCLENBQUE7QUFDL0IsY0FBYyxnQkFBZ0IsQ0FBQTtBQUU5QixNQUFNLENBQUMsTUFBTSxNQUFNLEdBQU8sWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFBIn0=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
packages/i18n/dist/lib/t.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

2
packages/i18n/dist/lib/t.js vendored Normal file
View File

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=

View File

@ -1,29 +1,14 @@
import * as TOML from 'smol-toml';
import { IOptions } from '../types.js';
import * as deepl from './deepl.js';
export declare const clean: (text?: string) => string;
export declare const hash: (text: string) => string;
export declare const translateObjectAIT: (obj: any, src: string, options: IOptions) => Promise<any>;
export declare const translateXLS: (src: string, dst: string, options: IOptions) => Promise<any>;
export declare const translateDeepL: (text: string, srcLang: string, dstLang: string, dOptions: deepl.IDeepLOptions, options?: IOptions, file?: string) => Promise<any>;
export declare const translateObject: (obj: any, src: string, options: IOptions) => Promise<any>;
export declare const getTranslation: (translations: any, all?: boolean) => any;
export declare const translateMarkup: (src: string, dst: string, options: IOptions) => Promise<any>;
export declare const translateJSON: (src: string, dst: string, options: IOptions) => Promise<any>;
export declare const translateTOML: (src: string, dst: string, options: IOptions) => Promise<any>;
export declare const translateYAML: (src: string, dst: string, options: IOptions) => Promise<string | Record<string, TOML.TomlPrimitive>>;
export declare const translateFiles: (file: any, targets: string[], options: IOptions) => Promise<false | any[]>;
export declare const translate: (opts: IOptions) => Promise<any[]>;
export declare const translateText: (text: string, srcLang: string, dstLang: string, options?: IOptions) => Promise<any>;
export declare const storeSet: (storePath: string, text: string, translation: string, file?: string) => void;
export declare const storeGet: (storePath: string, text: string, file?: string) => any;
export declare const TRANSLATORS: {
'.md': (src: string, dst: string, options: IOptions) => Promise<any>;
'.html': (src: string, dst: string, options: IOptions) => Promise<any>;
'.json': (src: string, dst: string, options: IOptions) => Promise<any>;
'.toml': (src: string, dst: string, options: IOptions) => Promise<any>;
'.yaml': (src: string, dst: string, options: IOptions) => Promise<string | Record<string, TOML.TomlPrimitive>>;
'.yaml': (src: string, dst: string, options: IOptions) => Promise<string | Record<string, import("smol-toml").TomlPrimitive>>;
'.xlsx': (src: string, dst: string, options: IOptions) => Promise<any>;
'.xls': (src: string, dst: string, options: IOptions) => Promise<any>;
'.txt': (text: string, srcLang: string, dstLang: string, options?: IOptions) => Promise<any>;
};
export declare const getTranslator: (file: string) => any;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,11 @@
import { IOptions } from '../types.js';
import * as deepl from './deepl.js';
export declare let logger: import("tslog").Logger;
export declare const clean: (text?: string) => string;
export declare const extension: (file: string) => string;
export declare const getTranslation: (translations: any, all?: boolean) => any;
export declare const storeSet: (storePath: string, text: string, translation: string, file?: string) => void;
export declare const storeGet: (storePath: string, text: string, file?: string) => any;
export declare const translateObjectAIT: (obj: any, src: string, options: IOptions) => Promise<any>;
export declare const translateDeepL: (text: string, srcLang: string, dstLang: string, dOptions: deepl.IDeepLOptions, options?: IOptions, file?: string) => Promise<any>;
export declare const translateObject: (obj: any, src: string, options: IOptions) => Promise<any>;

File diff suppressed because one or more lines are too long

View File

@ -2,5 +2,8 @@ import { IOptions } from '../types.js';
import * as deepl from './deepl.js';
export declare const clean: (text?: string) => string;
export declare const hash: (text: string) => string;
export declare const getTranslation: (translations: any, all?: boolean) => any;
export declare const storeSet: (storePath: string, text: string, translation: string, file?: string) => void;
export declare const storeGet: (storePath: string, text: string, file?: string) => any;
export declare const translateDeepL: (text: string, srcLang: string, dstLang: string, dOptions: deepl.IDeepLOptions, options?: IOptions, file?: string) => Promise<any>;
export declare const translateText: (text: string, srcLang: string, dstLang: string, options?: IOptions) => Promise<string>;
export declare const translateText: (text: string, srcLang: string, dstLang: string, options?: IOptions) => Promise<any>;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
import { IOptions } from '../types.js';
export declare const translateJSON: (src: string, dst: string, options: IOptions) => Promise<any>;

View File

@ -0,0 +1,21 @@
import { OSR_CACHE } from '@polymech/commons';
import { get_cached, set_cached } from '@polymech/cache';
import { sync as read } from "@polymech/fs/read";
import { sync as write } from "@polymech/fs/write";
import { MODULE_NAME } from '../constants.js';
import { translateObject } from './translate_commons.js';
export const translateJSON = async (src, dst, options) => {
const osr_cache = OSR_CACHE();
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return cached;
}
let object = read(src, 'json');
object = await translateObject(object, src, options);
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, object);
}
write(dst, object);
return object;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX2pzb24gY29weS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdHJhbnNsYXRlX2pzb24gY29weS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDN0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUN4RCxPQUFPLEVBQUUsSUFBSSxJQUFJLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFFbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxlQUFlLEVBQVUsTUFBTSx3QkFBd0IsQ0FBQTtBQUVoRSxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUM5QixHQUFXLEVBQ1gsR0FBVyxFQUNYLE9BQWlCLEVBQUUsRUFBRTtJQUNyQixNQUFNLFNBQVMsR0FBRyxTQUFTLEVBQUUsQ0FBQTtJQUM3QixNQUFNLE1BQU0sR0FBRyxNQUFNLFVBQVUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBQ3pFLElBQUksU0FBUyxJQUFJLE1BQU0sSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkMsT0FBTyxNQUFNLENBQUE7SUFDakIsQ0FBQztJQUVELElBQUksTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFRLENBQUE7SUFDckMsTUFBTSxHQUFHLE1BQU0sZUFBZSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFFcEQsSUFBSSxTQUFTLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLE1BQU0sVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQ3RFLENBQUM7SUFDRCxLQUFLLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQ2xCLE9BQU8sTUFBTSxDQUFBO0FBQ2pCLENBQUMsQ0FBQSJ9

View File

@ -0,0 +1,2 @@
import { IOptions } from '../types.js';
export declare const translateJSON: (src: string, dst: string, options: IOptions) => Promise<any>;

View File

@ -0,0 +1,21 @@
import { OSR_CACHE } from '@polymech/commons';
import { get_cached, set_cached } from '@polymech/cache';
import { sync as read } from "@polymech/fs/read";
import { sync as write } from "@polymech/fs/write";
import { MODULE_NAME } from '../constants.js';
import { translateObject } from './translate_commons.js';
export const translateJSON = async (src, dst, options) => {
const osr_cache = OSR_CACHE();
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return cached;
}
let object = read(src, 'json');
object = await translateObject(object, src, options);
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, object);
}
write(dst, object);
return object;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX2pzb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL3RyYW5zbGF0ZV9qc29uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ3hELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUVsRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBVSxNQUFNLHdCQUF3QixDQUFBO0FBRWhFLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxLQUFLLEVBQzlCLEdBQVcsRUFDWCxHQUFXLEVBQ1gsT0FBaUIsRUFBRSxFQUFFO0lBQ3JCLE1BQU0sU0FBUyxHQUFHLFNBQVMsRUFBRSxDQUFBO0lBQzdCLE1BQU0sTUFBTSxHQUFHLE1BQU0sVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFDekUsSUFBSSxTQUFTLElBQUksTUFBTSxJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN2QyxPQUFPLE1BQU0sQ0FBQTtJQUNqQixDQUFDO0lBRUQsSUFBSSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQVEsQ0FBQTtJQUNyQyxNQUFNLEdBQUcsTUFBTSxlQUFlLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQTtJQUVwRCxJQUFJLFNBQVMsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDN0IsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDLENBQUE7SUFDdEUsQ0FBQztJQUNELEtBQUssQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLENBQUE7SUFDbEIsT0FBTyxNQUFNLENBQUE7QUFDakIsQ0FBQyxDQUFBIn0=

View File

@ -0,0 +1,2 @@
import { IOptions } from '../types.js';
export declare const translateMarkup: (src: string, dst: string, options: IOptions) => Promise<any>;

View File

@ -0,0 +1,30 @@
import { OSR_CACHE } from '@polymech/commons';
import { get_cached, set_cached } from '@polymech/cache';
import { sync as read } from "@polymech/fs/read";
import { sync as write } from "@polymech/fs/write";
import { MODULE_NAME } from '../constants.js';
import { translateDeepL, getTranslation } from './translate_commons.js';
export const translateMarkup = async (src, dst, options) => {
const osr_cache = OSR_CACHE();
const cached = await get_cached(src, { keys: options.keys, filters: options.filters }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return cached;
}
const srcContent = read(src);
let translations = await translateDeepL(srcContent, options.srcLang, options.dstLang, {
free_api: false,
auth_key: options.api_key
}, options, src);
translations = getTranslation(translations);
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys, filters: options.filters }, MODULE_NAME, translations);
}
if (translations) {
write(dst, translations);
}
else {
return false;
}
return translations;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX21hcmt1cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdHJhbnNsYXRlX21hcmt1cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDN0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUN4RCxPQUFPLEVBQUUsSUFBSSxJQUFJLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFFbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFFdkUsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLEtBQUssRUFDaEMsR0FBVyxFQUNYLEdBQVcsRUFDWCxPQUFpQixFQUFFLEVBQUU7SUFDckIsTUFBTSxTQUFTLEdBQUcsU0FBUyxFQUFFLENBQUE7SUFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUNwRyxJQUFJLFNBQVMsSUFBSSxNQUFNLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3ZDLE9BQU8sTUFBTSxDQUFBO0lBQ2pCLENBQUM7SUFDRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFXLENBQUE7SUFDdEMsSUFBSSxZQUFZLEdBQUcsTUFBTSxjQUFjLENBQUMsVUFBVSxFQUM5QyxPQUFPLENBQUMsT0FBTyxFQUNmLE9BQU8sQ0FBQyxPQUFPLEVBQ2Y7UUFDSSxRQUFRLEVBQUUsS0FBSztRQUNmLFFBQVEsRUFBRSxPQUFPLENBQUMsT0FBTztLQUNyQixFQUFFLE9BQU8sRUFBRSxHQUFHLENBQVEsQ0FBQTtJQUVsQyxZQUFZLEdBQUcsY0FBYyxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQzNDLElBQUksU0FBUyxJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM3QixNQUFNLFVBQVUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLFdBQVcsRUFBRSxZQUFZLENBQUMsQ0FBQTtJQUN0RyxDQUFDO0lBQ0QsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNmLEtBQUssQ0FBQyxHQUFHLEVBQUUsWUFBWSxDQUFDLENBQUE7SUFDNUIsQ0FBQztTQUFNLENBQUM7UUFDSixPQUFPLEtBQUssQ0FBQTtJQUNoQixDQUFDO0lBQ0QsT0FBTyxZQUFZLENBQUE7QUFDdkIsQ0FBQyxDQUFBIn0=

View File

@ -0,0 +1,2 @@
import { IOptions } from '../types.js';
export declare const translateText: (text: string, srcLang: string, dstLang: string, options?: IOptions) => Promise<any>;

View File

@ -0,0 +1,51 @@
import * as path from 'path';
import { resolve, CONFIG_DEFAULT } from '@polymech/commons';
import { sync as exists } from "@polymech/fs/exists";
import { logger, clean, storeGet, storeSet, translateDeepL, getTranslation } from './translate_commons.js';
export const translateText = async (text, srcLang, dstLang, options = {}) => {
if (!text || text.length === 0) {
return '';
}
if (srcLang === dstLang) {
return text;
}
if (!options.store) {
logger.error('No store provided');
return text;
}
const store = path.resolve(resolve(options.store, false));
if (!exists(store)) {
logger.warn(`Invalid store root : ${store}`);
}
const config = CONFIG_DEFAULT();
text = clean(text);
if (exists(options.store)) {
const stored = storeGet(options.store, text);
if (stored) {
return stored;
}
}
if (!options.storeRoot) {
options.storeRoot = "${OSR_ROOT}/i18n-store";
}
if (!options.api_key) {
if (!config || !config.deepl || !config.deepl.auth_key) {
logger.error('i18n:translateText: No API key provided');
return text;
}
options.api_key = config.deepl.auth_key;
}
const out = await translateDeepL(text, srcLang, dstLang, {
...config.deepl
}, options, "");
const translation = getTranslation(out, false);
if (translation) {
storeSet(options.store, text, translation);
return translation;
}
else {
logger.warn('Error translating : ', text);
}
return text;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX3RleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL3RyYW5zbGF0ZV90ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBQzVCLE9BQU8sRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0QsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUVwRCxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLGNBQWMsRUFBRSxjQUFjLEVBQUcsTUFBTSx3QkFBd0IsQ0FBQTtBQUUzRyxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLElBQVksRUFBRSxPQUFlLEVBQUUsT0FBZSxFQUFFLFVBQW9CLEVBQUUsRUFBRSxFQUFFO0lBRTFHLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUM3QixPQUFPLEVBQUUsQ0FBQTtJQUNiLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUN0QixPQUFPLElBQUksQ0FBQTtJQUNmLENBQUM7SUFDRCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2pCLE1BQU0sQ0FBQyxLQUFLLENBQUMsbUJBQW1CLENBQUMsQ0FBQTtRQUNqQyxPQUFPLElBQUksQ0FBQTtJQUNmLENBQUM7SUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUE7SUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ2pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0JBQXdCLEtBQUssRUFBRSxDQUFDLENBQUE7SUFDaEQsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFRLGNBQWMsRUFBRSxDQUFBO0lBQ3BDLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDbEIsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDeEIsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDNUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNULE9BQU8sTUFBTSxDQUFBO1FBQ2pCLENBQUM7SUFDTCxDQUFDO0lBQ0QsSUFBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUMsQ0FBQztRQUNuQixPQUFPLENBQUMsU0FBUyxHQUFHLHdCQUF3QixDQUFBO0lBQ2hELENBQUM7SUFDRCxJQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBQyxDQUFDO1FBQ2pCLElBQUcsQ0FBQyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUMsQ0FBQztZQUNuRCxNQUFNLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxDQUFDLENBQUE7WUFDdkQsT0FBTyxJQUFJLENBQUE7UUFDZixDQUFDO1FBQ0QsT0FBTyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQTtJQUMzQyxDQUFDO0lBQ0QsTUFBTSxHQUFHLEdBQWEsTUFBTSxjQUFjLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQzdEO1FBQ0ksR0FBRyxNQUFNLENBQUMsS0FBSztLQUNsQixFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQTtJQUVuQixNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO0lBQzlDLElBQUksV0FBVyxFQUFFLENBQUM7UUFDZCxRQUFRLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUE7UUFDMUMsT0FBTyxXQUFXLENBQUE7SUFDdEIsQ0FBQztTQUFNLENBQUM7UUFDSixNQUFNLENBQUMsSUFBSSxDQUFDLHNCQUFzQixFQUFFLElBQUksQ0FBQyxDQUFBO0lBQzdDLENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQTtBQUNmLENBQUMsQ0FBQSJ9

View File

@ -0,0 +1,2 @@
import { IOptions } from '../types.js';
export declare const translateTOML: (src: string, dst: string, options: IOptions) => Promise<any>;

View File

@ -0,0 +1,30 @@
import { OSR_CACHE } from '@polymech/commons';
import { get_cached, set_cached } from '@polymech/cache';
import { sync as read } from "@polymech/fs/read";
import { sync as write } from "@polymech/fs/write";
import * as TOML from 'smol-toml';
import { MODULE_NAME } from '../constants.js';
import { translateObject } from './translate_commons.js';
import { createLogger } from '@polymech/log';
const logger = createLogger('i18n');
export const translateTOML = async (src, dst, options) => {
logger.info(`Translating ${src} to ${dst}`);
const osr_cache = OSR_CACHE();
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return cached;
}
let srcContent = read(src);
let toml = TOML.parse(srcContent);
toml = await translateObject(toml, src, options);
if (osr_cache && options.cache) {
try {
await set_cached(src, { keys: options.keys }, MODULE_NAME, TOML.stringify(toml));
}
catch (e) {
logger.error(`Error caching ${src} TOML : ${e.message}`, toml);
}
}
write(dst, TOML.stringify(toml));
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX3RvbWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL3RyYW5zbGF0ZV90b21sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ3hELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUNsRCxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUVqQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHdCQUF3QixDQUFBO0FBQ3hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFFNUMsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0FBRW5DLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxLQUFLLEVBQzlCLEdBQVcsRUFDWCxHQUFXLEVBQ1gsT0FBaUIsRUFBRSxFQUFFO0lBRXJCLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxHQUFHLE9BQU8sR0FBRyxFQUFFLENBQUMsQ0FBQTtJQUMzQyxNQUFNLFNBQVMsR0FBRyxTQUFTLEVBQUUsQ0FBQTtJQUM3QixNQUFNLE1BQU0sR0FBRyxNQUFNLFVBQVUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBQ3pFLElBQUksU0FBUyxJQUFJLE1BQU0sSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkMsT0FBTyxNQUFNLENBQUE7SUFDakIsQ0FBQztJQUNELElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQVcsQ0FBQTtJQUNwQyxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ2pDLElBQUksR0FBRyxNQUFNLGVBQWUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBRWhELElBQUksU0FBUyxJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUM7WUFDRCxNQUFNLFVBQVUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7UUFDcEYsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxNQUFNLENBQUMsS0FBSyxDQUFDLGlCQUFpQixHQUFHLFdBQVcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ25FLENBQUM7SUFDTCxDQUFDO0lBQ0QsS0FBSyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7QUFDcEMsQ0FBQyxDQUFBIn0=

View File

@ -0,0 +1,2 @@
import { IOptions } from '../types.js';
export declare const translateXLS: (src: string, dst: string, options: IOptions) => Promise<any>;

56
packages/i18n/dist/lib/translate_xls.js vendored Normal file
View File

@ -0,0 +1,56 @@
import * as path from 'path';
import { JSONPath } from 'jsonpath-plus';
import { get_cached, set_cached } from '@polymech/cache';
import { OSR_CACHE } from '@polymech/commons';
import { sync as exists } from "@polymech/fs/exists";
import { sync as mkdir } from "@polymech/fs/dir";
import * as XLSX from 'xlsx';
import { MODULE_NAME } from '../constants.js';
import { logger, translateObjectAIT } from './translate_commons.js';
export const translateXLS = async (src, dst, options) => {
logger.debug(`Translating ${src} to ${dst}`);
if (!exists(src)) {
logger.error('File not found : ' + src);
return;
}
const dstDir = path.parse(dst).dir;
mkdir(dstDir);
const osr_cache = OSR_CACHE();
const cached = await get_cached(src, {
keys: options.keys
}, MODULE_NAME);
if (osr_cache && cached && options.cache && exists(dst)) {
return cached;
}
const workbook = XLSX.readFile(src);
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const raw_data = XLSX.utils.sheet_to_json(worksheet, { header: 1, blankrows: false, raw: false, skipHidden: true });
const queryResult = JSONPath({
path: options.query,
json: raw_data,
});
let translated;
try {
translated = await translateObjectAIT(raw_data, src, {
...options,
keys: queryResult
});
}
catch (error) {
logger.error('Error translating XLSX', error);
return;
}
if (!translated) {
logger.error('Error translating XLSX', src);
return;
}
const sheetOut = XLSX.utils.json_to_sheet(translated, { skipHeader: true });
const workbookOut = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbookOut, sheetOut, workbook.SheetNames[0]);
XLSX.writeFileXLSX(workbookOut, dst);
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, translated);
}
return translated;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX3hscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdHJhbnNsYXRlX3hscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUM1QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3hDLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDeEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEQsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUNoRCxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUM1QixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFFN0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFBO0FBRW5FLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxLQUFLLEVBQzdCLEdBQVcsRUFDWCxHQUFXLEVBQ1gsT0FBaUIsRUFBRSxFQUFFO0lBQ3JCLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxHQUFHLE9BQU8sR0FBRyxFQUFFLENBQUMsQ0FBQTtJQUM1QyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLG1CQUFtQixHQUFHLEdBQUcsQ0FBQyxDQUFBO1FBQ3ZDLE9BQU07SUFDVixDQUFDO0lBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUE7SUFDbEMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQ2IsTUFBTSxTQUFTLEdBQUcsU0FBUyxFQUFFLENBQUE7SUFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2pDLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtLQUNyQixFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBRWYsSUFBSSxTQUFTLElBQUksTUFBTSxJQUFJLE9BQU8sQ0FBQyxLQUFLLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDdEQsT0FBTyxNQUFNLENBQUE7SUFDakIsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUE7SUFDbkMsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUQsTUFBTSxRQUFRLEdBQVUsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsU0FBUyxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDM0gsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUN4QjtRQUNJLElBQUksRUFBRSxPQUFPLENBQUMsS0FBSztRQUNuQixJQUFJLEVBQUUsUUFBUTtLQUVqQixDQUFDLENBQUE7SUFDTixJQUFJLFVBQVUsQ0FBQTtJQUNkLElBQUksQ0FBQztRQUNELFVBQVUsR0FBRyxNQUFNLGtCQUFrQixDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDakQsR0FBRyxPQUFPO1lBQ1YsSUFBSSxFQUFFLFdBQVc7U0FDcEIsQ0FBQyxDQUFBO0lBQ04sQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDYixNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFLEtBQUssQ0FBQyxDQUFBO1FBQzdDLE9BQU07SUFDVixDQUFDO0lBQ0QsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2QsTUFBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsRUFBRSxHQUFHLENBQUMsQ0FBQTtRQUMzQyxPQUFNO0lBQ1YsQ0FBQztJQUNELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQzNFLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUE7SUFDekMsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUMzRSxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUNwQyxJQUFJLFNBQVMsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDN0IsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxXQUFXLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDMUUsQ0FBQztJQUNELE9BQU8sVUFBVSxDQUFBO0FBQ3JCLENBQUMsQ0FBQSJ9

View File

@ -0,0 +1,3 @@
import { IOptions } from '../types.js';
import * as TOML from 'smol-toml';
export declare const translateYAML: (src: string, dst: string, options: IOptions) => Promise<string | Record<string, TOML.TomlPrimitive>>;

View File

@ -0,0 +1,31 @@
import { OSR_CACHE } from '@polymech/commons';
import { get_cached, set_cached } from '@polymech/cache';
import { sync as read } from "@polymech/fs/read";
import { sync as write } from "@polymech/fs/write";
import { parse, stringify } from 'yaml';
import { MODULE_NAME } from '../constants.js';
import { translateObject, logger } from './translate_commons.js';
import * as TOML from 'smol-toml';
export const translateYAML = async (src, dst, options) => {
const osr_cache = OSR_CACHE();
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return TOML.parse(cached.translations);
}
let srcContent = read(src);
let yaml = parse(srcContent);
yaml = await translateObject(yaml, src, options);
if (osr_cache && options.cache) {
try {
await set_cached(src, { keys: options.keys }, MODULE_NAME, TOML.stringify({ translations: yaml }));
}
catch (e) {
logger.error(`Error caching YAML ${src} : ${e.message}`, yaml);
}
}
const ret = stringify(yaml);
write(dst, ret);
options.stdout && process.stdout.write(ret);
return ret;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlX3lhbWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL3RyYW5zbGF0ZV95YW1sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ3hELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQTtBQUV2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUNoRSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUVqQyxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsT0FBaUIsRUFBRSxFQUFFO0lBQy9FLE1BQU0sU0FBUyxHQUFHLFNBQVMsRUFBRSxDQUFBO0lBQzdCLE1BQU0sTUFBTSxHQUFHLE1BQU0sVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFDekUsSUFBSSxTQUFTLElBQUksTUFBTSxJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN2QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQzFDLENBQUM7SUFDRCxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFXLENBQUE7SUFDcEMsSUFBSSxJQUFJLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQzVCLElBQUksR0FBRyxNQUFNLGVBQWUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQ2hELElBQUksU0FBUyxJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUM7WUFDRCxNQUFNLFVBQVUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQTtRQUN0RyxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNULE1BQU0sQ0FBQyxLQUFLLENBQUMsc0JBQXNCLEdBQUcsTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDbkUsQ0FBQztJQUNMLENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDM0IsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUNmLE9BQU8sQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUE7SUFDM0MsT0FBTyxHQUFHLENBQUE7QUFDZCxDQUFDLENBQUEifQ==

View File

@ -19,8 +19,16 @@
"require": "./dist/lib/index.cjs"
},
"./translate": {
"import": "./dist/lib/translate_ex.js",
"require": "./dist/lib/translate_ex.cjs"
"import": "./dist/lib/translate.js",
"require": "./dist/lib/translate.cjs"
},
"./translate_text": {
"import": "./dist/lib/translate_text.js",
"require": "./dist/lib/translate_text.cjs"
},
"./glossary": {
"import": "./dist/lib/glossary.js",
"require": "./dist/lib/glossary.cjs"
}
},
"dependencies": {

View File

@ -1,10 +1,9 @@
export { Logger } from 'tslog'
import { createLogger } from '@polymech/log'
export { MODULE_NAME } from './constants.js'
export { sanitize } from './_cli.js'
export * from './lib/index.js'
export * from './options.js'
export * from './types.js'
export * from './zod_schema.js'

View File

@ -99,12 +99,11 @@ export async function transformPath(
const exampleTransformFunction: AsyncTransformer = async (input: string, path: string): Promise<string> => {
if (input === 'random') throw new Error('API error')
console.log('translate : ' + input)
return input.toUpperCase()
}
export const defaultError: ErrorCallback = (path: string, value: string, error: any): void => {
console.error(`Error at path: ${path}, value: ${value}, error: ${error}`)
// logger.error(`Error at path: ${path}, value: ${value}, error: ${error}`)
}
export const defaultOptions = (options: TransformOptions = {} as TransformOptions): TransformOptions => {
@ -118,17 +117,3 @@ export const defaultOptions = (options: TransformOptions = {} as TransformOption
...options
}
}
const data = {}
const runTransformation = async (): Promise<void> => {
// const testTransformFunction = testFilters([isNumber, isBoolean])
const options: TransformOptions = defaultOptions();
try {
await transformObject(data, options.transform, options.path, options.throttleDelay, options.concurrentTasks, options.errorCallback, options.filterCallback);
console.log('Transformed object:', data);
console.log('All transformations were successful.');
} catch (error) {
console.error('Transformation failed:', error);
}
}

View File

@ -25,6 +25,7 @@ export const glossaryPath = (storeRoot, srcLang, dstLang) =>
path.resolve(resolve(`${storeRoot}/glossary/${srcLang}/${dstLang}/${GLOSSARY_FILE_NAME}`))
export const meta = (storeRoot: string, srcLang: string, dstLang: string): deepl.IGlossary | null => {
const filePath = glossaryMetaPath(storeRoot, srcLang, dstLang)
if (exists(filePath)) {
return (read(filePath, 'json') as deepl.IGlossary)

View File

@ -1,365 +1,17 @@
import * as path from 'path'
import { JSONPath } from 'jsonpath-plus'
import { createHash } from 'crypto'
import { get_cached, set_cached } from '@polymech/cache'
import { OSR_CACHE } from '@polymech/commons'
import { CONFIG_DEFAULT } from '@polymech/commons'
import { resolve } from '@polymech/commons'
import { isString, isArray, isObject, isNumber } from '@polymech/core/primitives'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import { sync as exists } from "@polymech/fs/exists"
import { sync as mkdir } from "@polymech/fs/dir"
import * as XLSX from 'xlsx'
import { parse, stringify } from 'yaml'
import pMap from 'p-map'
import { minify as minify_html } from 'html-minifier-terser'
import { globBase } from '@polymech/commons'
// import * as TOML from '@iarna/toml'
import * as TOML from 'smol-toml'
import {
targets,
parse as parseOptions
} from '../options.js'
import { globBase } from '@polymech/commons'
import { MODULE_NAME } from '../constants.js'
import { IOptions, TranslateFilter } from '../types.js'
import { store, get } from './store.js'
import * as deepl from './deepl.js'
import { targets,parse as parseOptions } from '../options.js'
import { IOptions } from '../types.js'
import { translateMarkup } from './translate_markup.js'
import { translateJSON } from './translate_json.js'
import { translateTOML } from './translate_toml.js'
import { translateYAML } from './translate_yaml.js'
import { translateXLS } from './translate_xls.js'
import { translateText } from './translate_text.js'
import { extension, getTranslation, logger, translateDeepL } from './translate_commons.js'
import { createLogger } from '@polymech/log'
let logger = createLogger('i18n')
const minify = false
const extension = (file: string) => path.parse(file).ext
import {
defaultFilters,
defaultOptions,
transformObject,
TransformOptions,
testFilters
} from './async-iterator.js'
import { update } from './glossary.js'
export const clean = (text: string = "") => text.trim()
export const hash = (text: string) => createHash('md5').update(clean(text)).digest('base64')
export const translateObjectAIT = async (obj: any, src: string, options: IOptions) => {
const opts: TransformOptions = defaultOptions({
throttleDelay: 100,
concurrentTasks: 1,
path: options.query,
filterCallback: testFilters(
defaultFilters([
async (input) => !options.keys.includes(input)
])
),
transform: async (input: string, path: string) => {
if((isNumber(input) || parseInt(input))){
return input
}
const stored = get(options.store, input as string, options)
if (stored) {
return stored
} else {
const translated = await _translate(input, src, options)
if (translated) {
if (options.store) {
store(options.store, input, translated, options)
}
return translated
}
return input
}
},
errorCallback: (path: string, value: string, error: any) => {
logger.error(`Error at path: ${path}, value: ${value}, error: ${error}`)
return value
}
} as TransformOptions)
try {
await transformObject(obj, opts.transform, opts.path, opts.throttleDelay, opts.concurrentTasks, opts.errorCallback, opts.filterCallback)
return obj
} catch (error) {
logger.error('Translation failed:', error)
}
}
export const translateXLS = async (
src: string,
dst: string,
options: IOptions) => {
logger.debug(`Translating ${src} to ${dst}`)
if (!exists(src)) {
logger.error('File not found : ' + src)
return
}
const dstDir = path.parse(dst).dir
mkdir(dstDir)
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, {
keys: options.keys
}, MODULE_NAME)
if (osr_cache && cached && options.cache && exists(dst)) {
return cached
}
const workbook = XLSX.readFile(src)
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const raw_data: any[] = XLSX.utils.sheet_to_json(worksheet, { header: 1, blankrows: false, raw: false, skipHidden: true });
const queryResult = JSONPath(
{
path: options.query,
json: raw_data,
})
let translated
try {
translated = await translateObjectAIT(raw_data, src, {
...options,
keys: queryResult
})
} catch (error) {
logger.error('Error translating XLSX', error)
return
}
if (!translated) {
logger.error('Error translating XLSX', src)
return
}
const sheetOut = XLSX.utils.json_to_sheet(translated, { skipHeader: true })
const workbookOut = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbookOut, sheetOut, workbook.SheetNames[0])
XLSX.writeFileXLSX(workbookOut, dst)
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, translated)
}
return translated
}
export const translateDeepL = async (
text: string,
srcLang: string = 'EN',
dstLang: string = 'DE',
dOptions: deepl.IDeepLOptions,
options: IOptions = {},
file: string = '') => {
if (minify) {
text = await minify_html(text, {
collapseWhitespace: true
})
}
const glossary = await update(srcLang.toLowerCase(), dstLang.toLowerCase(), options)
const deeplOptions = {
preserve_formatting: '1',
tag_handling: ["xml"],
...dOptions,
text: text,
target_lang: dstLang as deepl.DeepLLanguages,
source_lang: srcLang as deepl.DeepLLanguages,
glossary_id: glossary?.glossaryId,
formality: options.formality || 'default',
} as deepl.IDeepLOptions
let ret: any = await deepl.translate_deepl(deeplOptions) as deepl.IDeepLResponse
if (!ret) {
logger.error('Translate failed : ' + text, file)
return false
}
ret = ret?.data
if (options.filters) {
(ret.translations).forEach((t, i) => {
(options.filters as TranslateFilter[]).forEach((f) => {
ret.translations[i].text = f(text, t.text, file)
})
})
}
return ret.translations
}
const _translate = async (value: string, src: string, options: IOptions) => {
const translations = await translateDeepL(value as string, options.srcLang, options.dstLang,
{
auth_key: options.api_key,
formality: options.formality || 'default',
free_api: false
} as any, options, src)
return getTranslation(translations)
}
export const translateObject = async (obj: any, src: string, options: IOptions) => {
if (isNumber(obj)) {
return obj
}
if (isString(obj) && !obj.trim().length) {
return obj
}
if (isString(obj) && options.store) {
const stored = get(options.store, obj as string, options)
if (stored && options.cache) {
return stored
}
const ret = await _translate(obj as string, src, options)
if (ret && options.store) {
store(options.store, obj, ret, options)
return ret
} else {
console.error('Error translating : ', obj)
}
return obj
}
if (isObject(obj) || isArray(obj)) {
for await (const [key, value] of Object.entries(obj)) {
if (!obj[key]) {
continue
}
if (!isString(key)) {
continue
}
if (isString(value) && options.keys && !options.keys.includes(key)) {
continue
}
if (isString(value)) {
const stored = get(options.store, value as string, options)
if (stored && options.cache) {
obj[key] = stored
} else {
obj[key] = await _translate(value as string, src, options)
if (options.store) {
store(options.store, value, obj[key], options)
}
}
} else if (isObject(value)) {
obj[key] = await translateObject(value, src, options)
} else if (isArray(value)) {
let i = 0
for await (const v of value) {
if (!v) continue
value[i] = await translateObject(v, src, options)
i++
}
}
}
}
return obj
}
export const getTranslation = (translations: any, all: boolean = false) => {
if (!all) {
if (translations && translations[0] && translations[0].text) {
return translations[0].text
}
} else {
return translations
}
return false
}
export const translateMarkup = async (
src: string,
dst: string,
options: IOptions) => {
logger.info(`Translating ${src} to ${dst}`);
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys, filters: options.filters }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return cached
}
const srcContent = read(src) as string
let translations = await translateDeepL(srcContent,
options.srcLang,
options.dstLang,
{
free_api: false,
auth_key: options.api_key
} as any, options, src) as any
translations = getTranslation(translations)
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys, filters: options.filters }, MODULE_NAME, translations)
}
if (translations) {
write(dst, translations)
} else {
return false
}
return translations
}
export const translateJSON = async (
src: string,
dst: string,
options: IOptions) => {
logger.info(`Translating ${src} to ${dst}`)
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME)
if (osr_cache && cached && options.cache) {
return cached
}
let object = read(src, 'json') as any
object = await translateObject(object, src, options)
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, object)
}
write(dst, object)
return object
}
export const translateTOML = async (
src: string,
dst: string,
options: IOptions) => {
logger.info(`Translating ${src} to ${dst}`)
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME)
if (osr_cache && cached && options.cache) {
return cached
}
let srcContent = read(src) as string
let toml = TOML.parse(srcContent)
toml = await translateObject(toml, src, options)
if (osr_cache && options.cache) {
try {
await set_cached(src, { keys: options.keys }, MODULE_NAME, TOML.stringify(toml))
} catch (e) {
logger.error(`Error caching ${src} TOML : ${e.message}`, toml);
}
}
write(dst, TOML.stringify(toml))
}
export const translateYAML = async (src: string, dst: string, options: IOptions) => {
logger.debug(`Translating ${src} to ${dst}`)
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME)
if (osr_cache && cached && options.cache) {
return TOML.parse(cached.translations)
}
let srcContent = read(src) as string
let yaml = parse(srcContent)
yaml = await translateObject(yaml, src, options)
// yaml = await translateObjectAIT(yaml, src, options)
if (osr_cache && options.cache) {
try {
await set_cached(src, { keys: options.keys }, MODULE_NAME, TOML.stringify({ translations: yaml }))
} catch (e) {
logger.error(`Error caching YAML ${src} : ${e.message}`, yaml);
}
}
const ret = stringify(yaml)
write(dst, ret)
options.stdout && process.stdout.write(ret)
return ret
}
export const translateFiles = async (
file, targets: string[], options: IOptions) => {
const translator = getTranslator(file)
@ -373,6 +25,7 @@ export const translateFiles = async (
}
return await pMap(targets, async (target) => getTranslator(file)(file, target, options), { concurrency: 1 })
}
export const translate = async (opts: IOptions) => {
opts = parseOptions(opts as any, {})
if (!opts.api_key) {
@ -426,64 +79,7 @@ export const translate = async (opts: IOptions) => {
logger.debug(`Translated all: ${opts.text ? opts.text : opts.src} to ${languages}`)
return translated
}
export const translateText = async (text: string, srcLang: string, dstLang: string, options: IOptions = {}) => {
if (!text || text.length === 0) {
return ''
}
if (srcLang === dstLang) {
return text
}
if (!options.store) {
logger.error('No store provided')
return text
}
const store = path.resolve(resolve(options.store, false))
if (!exists(store)) {
logger.warn(`Invalid store root : ${store}`)
}
const config: any = CONFIG_DEFAULT()
text = clean(text)
if (exists(options.store)) {
const stored = storeGet(options.store, text)
if (stored) {
return stored
}
}
if(!options.storeRoot){
options.storeRoot = "${OSR_ROOT}/i18n-store"
}
if(!options.api_key){
if(!config || !config.deepl || !config.deepl.auth_key){
logger.error('i18n:translateText: No API key provided')
return text
}
options.api_key = config.deepl.auth_key
}
const out: string[] = await translateDeepL(text, srcLang, dstLang,
{
...config.deepl
}, options, "")
const translation = getTranslation(out, false)
if (translation) {
storeSet(options.store, text, translation)
return translation
} else {
logger.warn('Error translating : ', text)
}
return text
}
export const storeSet = (storePath: string, text: string, translation: string, file: string = '') => {
const store = read(storePath, 'json') || {}
store[text] = clean(translation)
write(storePath, store)
}
export const storeGet = (storePath: string, text: string, file: string = '') => {
const db = read(storePath, 'json') || {}
if (db[text]) {
return db[text]
}
}
export const TRANSLATORS =
{
'.md': translateMarkup,
@ -492,6 +88,7 @@ export const TRANSLATORS =
'.toml': translateTOML,
'.yaml': translateYAML,
'.xlsx': translateXLS,
'.xls': translateXLS
'.xls': translateXLS,
'.txt': translateText
}
export const getTranslator = (file: string) => TRANSLATORS[extension(file)]

View File

@ -0,0 +1,197 @@
import * as path from 'path'
import { isString, isArray, isObject, isNumber } from '@polymech/core/primitives'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import { minify as minify_html } from 'html-minifier-terser'
import { IOptions, TranslateFilter } from '../types.js'
import { store, get } from './store.js'
import * as deepl from './deepl.js'
const minify = false
import {
defaultFilters,
defaultOptions,
transformObject,
TransformOptions,
testFilters
} from './async-iterator.js'
import { update } from './glossary.js'
import { createLogger } from '@polymech/log'
export let logger = createLogger('i18n')
export const clean = (text: string = "") => text.trim()
export const extension = (file: string) => path.parse(file).ext
export const getTranslation = (translations: any, all: boolean = false) => {
if (!all) {
if (translations && translations[0] && translations[0].text) {
return translations[0].text
}
} else {
return translations
}
return false
}
export const storeSet = (storePath: string, text: string, translation: string, file: string = '') => {
const store = read(storePath, 'json') || {}
store[text] = clean(translation)
write(storePath, store)
}
export const storeGet = (storePath: string, text: string, file: string = '') => {
const db = read(storePath, 'json') || {}
if (db[text]) {
return db[text]
}
}
export const translateObjectAIT = async (obj: any, src: string, options: IOptions) => {
const opts: TransformOptions = defaultOptions({
throttleDelay: 100,
concurrentTasks: 1,
path: options.query,
filterCallback: testFilters(
defaultFilters([
async (input) => !options.keys.includes(input)
])
),
transform: async (input: string, path: string) => {
if((isNumber(input) || parseInt(input))){
return input
}
const stored = get(options.store, input as string, options)
if (stored) {
return stored
} else {
const translated = await _translate(input, src, options)
if (translated) {
if (options.store) {
store(options.store, input, translated, options)
}
return translated
}
return input
}
},
errorCallback: (path: string, value: string, error: any) => {
logger.error(`Error at path: ${path}, value: ${value}, error: ${error}`)
return value
}
} as TransformOptions)
try {
await transformObject(obj, opts.transform, opts.path, opts.throttleDelay, opts.concurrentTasks, opts.errorCallback, opts.filterCallback)
return obj
} catch (error) {
logger.error('Translation failed:', error)
}
}
export const translateDeepL = async (
text: string,
srcLang: string = 'EN',
dstLang: string = 'DE',
dOptions: deepl.IDeepLOptions,
options: IOptions = {},
file: string = '') => {
if (minify) {
text = await minify_html(text, {
collapseWhitespace: true
})
}
const glossary = await update(srcLang.toLowerCase(), dstLang.toLowerCase(), options)
const deeplOptions = {
preserve_formatting: '1',
tag_handling: ["xml"],
...dOptions,
text: text,
target_lang: dstLang as deepl.DeepLLanguages,
source_lang: srcLang as deepl.DeepLLanguages,
glossary_id: glossary?.glossaryId,
formality: options.formality || 'default',
} as deepl.IDeepLOptions
let ret: any = await deepl.translate_deepl(deeplOptions) as deepl.IDeepLResponse
if (!ret) {
logger.error('Translate failed : ' + text, file)
return false
}
ret = ret?.data
if (options.filters) {
(ret.translations).forEach((t, i) => {
(options.filters as TranslateFilter[]).forEach((f) => {
ret.translations[i].text = f(text, t.text, file)
})
})
}
return ret.translations
}
const _translate = async (value: string, src: string, options: IOptions) => {
const translations = await translateDeepL(value as string, options.srcLang, options.dstLang,
{
auth_key: options.api_key,
formality: options.formality || 'default',
free_api: false
} as any, options, src)
return getTranslation(translations)
}
export const translateObject = async (obj: any, src: string, options: IOptions) => {
if (isNumber(obj)) {
return obj
}
if (isString(obj) && !obj.trim().length) {
return obj
}
if (isString(obj) && options.store) {
const stored = get(options.store, obj as string, options)
if (stored && options.cache) {
return stored
}
const ret = await _translate(obj as string, src, options)
if (ret && options.store) {
store(options.store, obj, ret, options)
return ret
} else {
console.error('Error translating : ', obj)
}
return obj
}
if (isObject(obj) || isArray(obj)) {
for await (const [key, value] of Object.entries(obj)) {
if (!obj[key]) {
continue
}
if (!isString(key)) {
continue
}
if (isString(value) && options.keys && !options.keys.includes(key)) {
continue
}
if (isString(value)) {
const stored = get(options.store, value as string, options)
if (stored && options.cache) {
obj[key] = stored
} else {
obj[key] = await _translate(value as string, src, options)
if (options.store) {
store(options.store, value, obj[key], options)
}
}
} else if (isObject(value)) {
obj[key] = await translateObject(value, src, options)
} else if (isArray(value)) {
let i = 0
for await (const v of value) {
if (!v) continue
value[i] = await translateObject(v, src, options)
i++
}
}
}
}
return obj
}

View File

@ -1,105 +0,0 @@
import * as path from 'path'
import { createHash } from 'crypto'
import { CONFIG_DEFAULT } from '@polymech/commons'
import { resolve } from '@polymech/commons'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import { sync as exists } from "@polymech/fs/exists"
import { IOptions, TranslateFilter } from '../types.js'
import { store, get } from './store.js'
import * as deepl from './deepl.js'
import { createLogger } from '@polymech/log'
let logger = createLogger('i18n')
import { update } from './glossary.js'
export const clean = (text: string = "") => text.trim()
export const hash = (text: string) => createHash('md5').update(clean(text)).digest('base64')
export const translateDeepL = async (
text: string,
srcLang: string = 'EN',
dstLang: string = 'DE',
dOptions: deepl.IDeepLOptions,
options: IOptions = {},
file: string = '') => {
const glossary = await update(srcLang.toLowerCase(), dstLang.toLowerCase(), options)
const deeplOptions = {
preserve_formatting: '1',
tag_handling: ["xml"],
...dOptions,
text: text,
target_lang: dstLang as deepl.DeepLLanguages,
source_lang: srcLang as deepl.DeepLLanguages,
glossary_id: glossary?.glossaryId,
formality: options.formality || 'default',
} as deepl.IDeepLOptions
let ret: any = await deepl.translate_deepl(deeplOptions) as deepl.IDeepLResponse
if (!ret) {
logger.error('Translate failed : ' + text, file)
return false
}
ret = ret?.data
if (options.filters) {
(ret.translations).forEach((t, i) => {
(options.filters as TranslateFilter[]).forEach((f) => {
ret.translations[i].text = f(text, t.text, file)
})
})
}
return ret.translations
}
export const translateText = async (text: string, srcLang: string, dstLang: string, options: IOptions = {}) => {
/*
if (!text || text.length === 0) {
return ''
}
if (srcLang === dstLang) {
return text
}
if (!options.store) {
logger.error('No store provided')
return text
}
const store = path.resolve(resolve(options.store, false))
if (!exists(store)) {
logger.warn(`Invalid store root : ${store}`)
}
const config: any = CONFIG_DEFAULT()
text = clean(text)
if (exists(options.store)) {
const stored = storeGet(options.store, text)
if (stored) {
return stored
}
}
if(!options.storeRoot){
options.storeRoot = "${OSR_ROOT}/i18n-store"
}
if(!options.api_key){
if(!config || !config.deepl || !config.deepl.auth_key){
logger.error('i18n:translateText: No API key provided')
return text
}
options.api_key = config.deepl.auth_key
}
const out: string[] = await translateDeepL(text, srcLang, dstLang,
{
...config.deepl
}, options, "")
const translation = getTranslation(out, false)
if (translation) {
// storeSet(options.store, text, translation)
return translation
} else {
logger.warn('Error translating : ', text)
}
*/
return text
}

View File

@ -0,0 +1,27 @@
import { OSR_CACHE } from '@polymech/commons'
import { get_cached, set_cached } from '@polymech/cache'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import { IOptions } from '../types.js'
import { MODULE_NAME } from '../constants.js'
import { translateObject, logger } from './translate_commons.js'
export const translateJSON = async (
src: string,
dst: string,
options: IOptions) => {
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME)
if (osr_cache && cached && options.cache) {
return cached
}
let object = read(src, 'json') as any
object = await translateObject(object, src, options)
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, object)
}
write(dst, object)
return object
}

View File

@ -0,0 +1,37 @@
import { OSR_CACHE } from '@polymech/commons'
import { get_cached, set_cached } from '@polymech/cache'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import { IOptions } from '../types.js'
import { MODULE_NAME } from '../constants.js'
import { translateDeepL, getTranslation } from './translate_commons.js'
export const translateMarkup = async (
src: string,
dst: string,
options: IOptions) => {
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys, filters: options.filters }, MODULE_NAME);
if (osr_cache && cached && options.cache) {
return cached
}
const srcContent = read(src) as string
let translations = await translateDeepL(srcContent,
options.srcLang,
options.dstLang,
{
free_api: false,
auth_key: options.api_key
} as any, options, src) as any
translations = getTranslation(translations)
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys, filters: options.filters }, MODULE_NAME, translations)
}
if (translations) {
write(dst, translations)
} else {
return false
}
return translations
}

View File

@ -0,0 +1,55 @@
import * as path from 'path'
import { resolve, CONFIG_DEFAULT } from '@polymech/commons'
import { sync as exists } from "@polymech/fs/exists"
import { IOptions } from '../types.js'
import { logger, clean, storeGet, storeSet, translateDeepL, getTranslation } from './translate_commons.js'
export const translateText = async (text: string, srcLang: string, dstLang: string, options: IOptions = {}) => {
if (!text || text.length === 0) {
return ''
}
if (srcLang === dstLang) {
return text
}
if (!options.store) {
logger.error('No store provided')
return text
}
const store = path.resolve(resolve(options.store, false))
if (!exists(store)) {
logger.warn(`Invalid store root : ${store}`)
}
const config: any = CONFIG_DEFAULT()
text = clean(text)
if (exists(options.store)) {
const stored = storeGet(options.store, text)
if (stored) {
return stored
}
}
if(!options.storeRoot){
options.storeRoot = "${OSR_ROOT}/i18n-store"
}
if(!options.api_key){
if(!config || !config.deepl || !config.deepl.auth_key){
logger.error('i18n:translateText: No API key provided')
return text
}
options.api_key = config.deepl.auth_key
}
const out: string[] = await translateDeepL(text, srcLang, dstLang,
{
...config.deepl
}, options, "")
const translation = getTranslation(out, false)
if (translation) {
storeSet(options.store, text, translation)
return translation
} else {
logger.warn('Error translating : ', text)
}
return text
}

View File

@ -0,0 +1,36 @@
import { OSR_CACHE } from '@polymech/commons'
import { get_cached, set_cached } from '@polymech/cache'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import * as TOML from 'smol-toml'
import { IOptions } from '../types.js'
import { MODULE_NAME } from '../constants.js'
import { translateObject } from './translate_commons.js'
import { createLogger } from '@polymech/log'
const logger = createLogger('i18n')
export const translateTOML = async (
src: string,
dst: string,
options: IOptions) => {
logger.info(`Translating ${src} to ${dst}`)
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME)
if (osr_cache && cached && options.cache) {
return cached
}
let srcContent = read(src) as string
let toml = TOML.parse(srcContent)
toml = await translateObject(toml, src, options)
if (osr_cache && options.cache) {
try {
await set_cached(src, { keys: options.keys }, MODULE_NAME, TOML.stringify(toml))
} catch (e) {
logger.error(`Error caching ${src} TOML : ${e.message}`, toml);
}
}
write(dst, TOML.stringify(toml))
}

View File

@ -0,0 +1,63 @@
import * as path from 'path'
import { JSONPath } from 'jsonpath-plus'
import { get_cached, set_cached } from '@polymech/cache'
import { OSR_CACHE } from '@polymech/commons'
import { sync as exists } from "@polymech/fs/exists"
import { sync as mkdir } from "@polymech/fs/dir"
import * as XLSX from 'xlsx'
import { MODULE_NAME } from '../constants.js'
import { IOptions } from '../types.js'
import { logger, translateObjectAIT } from './translate_commons.js'
export const translateXLS = async (
src: string,
dst: string,
options: IOptions) => {
logger.debug(`Translating ${src} to ${dst}`)
if (!exists(src)) {
logger.error('File not found : ' + src)
return
}
const dstDir = path.parse(dst).dir
mkdir(dstDir)
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, {
keys: options.keys
}, MODULE_NAME)
if (osr_cache && cached && options.cache && exists(dst)) {
return cached
}
const workbook = XLSX.readFile(src)
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const raw_data: any[] = XLSX.utils.sheet_to_json(worksheet, { header: 1, blankrows: false, raw: false, skipHidden: true });
const queryResult = JSONPath(
{
path: options.query,
json: raw_data,
})
let translated
try {
translated = await translateObjectAIT(raw_data, src, {
...options,
keys: queryResult
})
} catch (error) {
logger.error('Error translating XLSX', error)
return
}
if (!translated) {
logger.error('Error translating XLSX', src)
return
}
const sheetOut = XLSX.utils.json_to_sheet(translated, { skipHeader: true })
const workbookOut = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbookOut, sheetOut, workbook.SheetNames[0])
XLSX.writeFileXLSX(workbookOut, dst)
if (osr_cache && options.cache) {
await set_cached(src, { keys: options.keys }, MODULE_NAME, translated)
}
return translated
}

View File

@ -0,0 +1,31 @@
import { OSR_CACHE } from '@polymech/commons'
import { get_cached, set_cached } from '@polymech/cache'
import { sync as read } from "@polymech/fs/read"
import { sync as write } from "@polymech/fs/write"
import { parse, stringify } from 'yaml'
import { IOptions } from '../types.js'
import { MODULE_NAME } from '../constants.js'
import { translateObject, logger } from './translate_commons.js'
import * as TOML from 'smol-toml'
export const translateYAML = async (src: string, dst: string, options: IOptions) => {
const osr_cache = OSR_CACHE()
const cached = await get_cached(src, { keys: options.keys }, MODULE_NAME)
if (osr_cache && cached && options.cache) {
return TOML.parse(cached.translations)
}
let srcContent = read(src) as string
let yaml = parse(srcContent)
yaml = await translateObject(yaml, src, options)
if (osr_cache && options.cache) {
try {
await set_cached(src, { keys: options.keys }, MODULE_NAME, TOML.stringify({ translations: yaml }))
} catch (e) {
logger.error(`Error caching YAML ${src} : ${e.message}`, yaml);
}
}
const ret = stringify(yaml)
write(dst, ret)
options.stdout && process.stdout.write(ret)
return ret
}

View File

@ -4,7 +4,9 @@
"src/**/*.ts"
],
"files": [
"src/index.ts"
"src/index.ts",
"src/lib/index.ts",
"src/lib/translate.ts"
],
"compilerOptions": {
"strictNullChecks": false,