Skip to content

Commit

Permalink
v0.4.0 New version
Browse files Browse the repository at this point in the history
- Add new translator - Translators.LibreTranslate.
- Defined translators "API" has been changed again, configuration must be updated. DefinedTranslators has been renamed to Translators. Every pre-defined translator is a function now. It's for translators to have configuration parameters like api key and stuff like that. Instead of `DefinedTranslators.GOOGLE_TRANSLATE` you should use `Translators.GoogleTranslate()`. Debug translators have been moved to the `DefinedTranslators.debug` object. `Translators` can be extended by your own translators. Pre-defined translators cannot be deleted or modified (or at least not supposed to be).
- Configuration loading optimizations: it's now cached if you don't touch the profiles settings. It means a configuration code itself might not be executed on every new sentence. The functions passed to configuration parameters are called as before. Still, it's better not to include initialization logic in the outer scope of configuration scripts.
- Improve types in JS editor
- Add `URL`, `URLSearchParams`, node.js `net` variables to configs
  • Loading branch information
MRGRD56 committed Mar 25, 2024
1 parent 8d2bf1a commit 7aa0a9a
Show file tree
Hide file tree
Showing 16 changed files with 342 additions and 63 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "textractor-translator",
"productName": "TextractorTranslator",
"version": "0.3.2",
"version": "0.4.0",
"description": "Textractor Translator",
"main": ".webpack/main",
"scripts": {
Expand Down
19 changes: 15 additions & 4 deletions src/configuration/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,20 @@ export interface Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string>;
}

export interface LibreTranslatorConfig {
host?: string;
apiKey?: string;
format?: 'text' | 'html';
}

export interface DefinedTranslators {
GOOGLE_TRANSLATE: Translator,
X_IDENTITY: Translator,
X_INFINITE: Translator,
X_NONE: Translator
GoogleTranslate: () => Translator,
LibreTranslate: (config?: LibreTranslatorConfig) => Translator;
debug: {
Identity: () => Translator;
Infinite: () => Translator;
None: () => Translator;
}
}

export interface DisplayedTransformedText {
Expand All @@ -39,6 +48,8 @@ export interface Configuration {
source: string;
target: string;
};

transformOriginal?(sentence: Sentence): MultiTransformedText;

transformTranslated?(translatedText: string, originalSentence: Sentence): OptionalTransformedText;
}
26 changes: 15 additions & 11 deletions src/configuration/getConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ import safeEval from 'safe-eval';
import transformOriginal from '../transformation/transformOriginal';
import transformTranslated from '../transformation/transformTranslated';
import nodeConsole from '../utils/nodeConsole';
import {DefinedTranslatorsImpl} from '../translation/DefinedTranslators';
import httpRequest from '../utils/httpRequest';
import * as queryString from 'query-string';
import {DefinedTranslatorsImpl} from '../translation/DefinedTranslators';
import * as net from 'net';

interface CommonConfigContext {
config: Configuration;
common: object;
memory: object;
DefinedTranslators: DefinedTranslators;
Translators: DefinedTranslators;
httpRequest: typeof httpRequest;
queryString: typeof queryString
console: Console;
URL: typeof URL,
URLSearchParams: typeof URLSearchParams,
net: typeof net
}

interface CustomConfigContext extends CommonConfigContext {
Expand All @@ -35,9 +39,11 @@ const safeEvalVoid = (code: string, context?: Record<string, any>): void => {
const memory = {};

const getCommonConfiguration = (configSourceCode: string | undefined): CommonConfigContext => {
const definedTranslators = new DefinedTranslatorsImpl();

const context: CommonConfigContext = {
config: {
translator: DefinedTranslatorsImpl.INSTANCE.GOOGLE_TRANSLATE,
translator: definedTranslators.GoogleTranslate(),
languages: {
source: 'auto',
target: 'en'
Expand All @@ -47,10 +53,13 @@ const getCommonConfiguration = (configSourceCode: string | undefined): CommonCon
},
common: {},
memory,
DefinedTranslators: DefinedTranslatorsImpl.INSTANCE,
Translators: definedTranslators,
httpRequest,
queryString,
console
console,
URL,
URLSearchParams,
net
};

if (configSourceCode != null) {
Expand All @@ -72,14 +81,9 @@ const getConfiguration = (commonConfigSourceCode: string | undefined, configSour
}

const context: CustomConfigContext = {
common: commonConfigContext.common,
...commonConfigContext,
commonConfig: commonConfigContext.config,
config: {...commonConfigContext.config},
memory,
DefinedTranslators: DefinedTranslatorsImpl.INSTANCE,
httpRequest,
queryString,
console
};

safeEvalVoid(configSourceCode, context);
Expand Down
25 changes: 22 additions & 3 deletions src/configuration/getProfileConfig.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
import indexArrayBy from '../utils/indexArrayBy';
import {COMMON_PROFILE_ID} from '../windows/settings/profiles/constants';
import getConfiguration from './getConfiguration';
import type Store from 'electron-store';
import {Configuration} from './Configuration';
import initializeSavedProfiles from './initializeSavedProfiles';
import {StoreKeys} from '../constants/store-keys';
import SavedProfiles from '../windows/settings/profiles/SavedProfiles';
import ref from '../utils/ref';
import electronStore from '../electron-store/electronStore';
import store from '../electron-store/store';

const configurationCache = ref<Configuration>();

store.onDidChange(StoreKeys.SAVED_PROFILES, () => {
configurationCache.current = undefined;
});

electronStore.onDidChange(StoreKeys.SAVED_PROFILES, () => {
configurationCache.current = undefined;
});

const getProfileConfig = (profileId?: string): Configuration => {
const cache = configurationCache.current;
if (cache) {
return cache;
}

const getProfileConfig = (store: Store, profileId?: string): Configuration => {
const savedProfiles = store.get(StoreKeys.SAVED_PROFILES) as (SavedProfiles | undefined) ?? initializeSavedProfiles(store);
const savedProfilesMap = indexArrayBy(savedProfiles.profiles, 'id');

const commonProfile = savedProfilesMap.get(COMMON_PROFILE_ID);
const activeProfileId = profileId ?? savedProfiles.activeProfileId;
const activeProfile = activeProfileId ? savedProfilesMap.get(activeProfileId) : undefined;

return getConfiguration(commonProfile?.configSource, activeProfile?.configSource);
const result = getConfiguration(commonProfile?.configSource, activeProfile?.configSource);
configurationCache.current = result;
return result;
};

export default getProfileConfig;
3 changes: 1 addition & 2 deletions src/electron-store/initElectronStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import {BrowserWindow, ipcMain} from 'electron';
import Store from 'electron-store';
import nodeConsole from '../utils/nodeConsole';
import {electronStoreKeysSimple} from './electronStoreShared';
import store from './store';

export const initElectronStore = (): Store => {
const store = new Store();

nodeConsole.log('Creating handlers for electronStore')

for (const key of electronStoreKeysSimple) {
Expand Down
5 changes: 5 additions & 0 deletions src/electron-store/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Store from 'electron-store';

const store = new Store();

export default store;
51 changes: 27 additions & 24 deletions src/translation/DefinedTranslators.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import {DefinedTranslators, Translator} from '../configuration/Configuration';
import {DefinedTranslators, LibreTranslatorConfig} from '../configuration/Configuration';
import GoogleTranslator from './translators/GoogleTranslator';
import IdentityTranslator from './translators/utility/IdentityTranslator';
import InfiniteTranslator from './translators/utility/InfiniteTranslator';
import NoneTranslator from './translators/utility/NoneTranslator';
import LibreTranslator from './translators/LibreTranslator';

class IdentityTranslator implements Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
return Promise.resolve(text);
}
}

class NoneTranslator implements Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
return undefined as any;
}
}

class InfiniteTranslator implements Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
return new Promise<string>(() => {});
export class DefinedTranslatorsImpl implements DefinedTranslators {
constructor() {
Object.keys(this).forEach((keyName) => {
const key = keyName as keyof DefinedTranslatorsImpl;
Object.defineProperty(this, key, {
value: this[key],
writable: false,
configurable: false,
enumerable: true
});
});
}
}

export class DefinedTranslatorsImpl implements DefinedTranslators {
GOOGLE_TRANSLATE = new GoogleTranslator();
X_IDENTITY = new IdentityTranslator();
X_NONE = new NoneTranslator();
X_INFINITE = new InfiniteTranslator();
GoogleTranslate = () => {
return new GoogleTranslator();
};

public static INSTANCE: DefinedTranslators = new DefinedTranslatorsImpl();
LibreTranslate = (config?: LibreTranslatorConfig) => {
return new LibreTranslator(config || {});
};

private constructor() {}
debug = Object.freeze({
Identity: () => new IdentityTranslator(),
Infinite: () => new InfiniteTranslator(),
None: () => new NoneTranslator()
});
}
35 changes: 35 additions & 0 deletions src/translation/translators/LibreTranslator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import httpRequest from '../../utils/httpRequest';
import {LibreTranslatorConfig, Translator} from '../../configuration/Configuration';

class LibreTranslator implements Translator {
constructor(private readonly config: LibreTranslatorConfig) {
}

async translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
const host = this.config.host || 'https://libretranslate.com';
const url = new URL('/translate', host).toString();

const responseData: any = await httpRequest(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
q: text,
source: sourceLanguage,
target: targetLanguage,
format: this.config.format,
api_key: this.config.apiKey
})
}).then((response) => response.json());

if (!responseData || responseData.translatedText == null) {
console.error('LibreTranslator unable to translate: ', responseData);
throw responseData;
}

return responseData.translatedText as string;
}
}

export default LibreTranslator;
9 changes: 9 additions & 0 deletions src/translation/translators/utility/IdentityTranslator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {Translator} from '../../../configuration/Configuration';

class IdentityTranslator implements Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
return Promise.resolve(text);
}
}

export default IdentityTranslator;
9 changes: 9 additions & 0 deletions src/translation/translators/utility/InfiniteTranslator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {Translator} from '../../../configuration/Configuration';

class InfiniteTranslator implements Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
return new Promise<string>(() => {});
}
}

export default InfiniteTranslator;
9 changes: 9 additions & 0 deletions src/translation/translators/utility/NoneTranslator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {Translator} from '../../../configuration/Configuration';

class NoneTranslator implements Translator {
translate(text: string, sourceLanguage: string, targetLanguage: string): Promise<string> {
return undefined as any;
}
}

export default NoneTranslator;
5 changes: 1 addition & 4 deletions src/windows/main/logic/workTextractorPipe.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {listenToPipe} from '../../../textractorServer';
import {Configuration, OptionalTransformedText, Sentence} from '../../../configuration/Configuration';
import Store from 'electron-store';
import getProfileConfig from '../../../configuration/getProfileConfig';
import nodeConsole from '../../../utils/nodeConsole';

Expand Down Expand Up @@ -73,16 +72,14 @@ const showSentence = (
textContainerWrapper.scrollTo(0, textContainerWrapper.scrollHeight);
};

const store = new Store();

const workTextractorPipe = () => {
const textContainerWrapper = document.getElementById('text-wrapper')!;
const textContainer = document.getElementById('text')!;
const sampleTextContainer = document.getElementById('text-sample')!;

listenToPipe((sentence) => {
try {
const config = getProfileConfig(store);
const config = getProfileConfig();
const multiTransformedText = config.transformOriginal?.(sentence);
const transformedTexts = Array.isArray(multiTransformedText) ? multiTransformedText : [multiTransformedText];

Expand Down
42 changes: 28 additions & 14 deletions src/windows/settings/components/ProfileSourceEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,49 @@ import React, {FC, useEffect} from 'react';
import configurationDeclarations from "!!raw-loader!../../../configuration/Configuration";
// @ts-ignore
// eslint-disable-next-line
import electronRequestDeclarations from '!!raw-loader!electron-request/dist/index'
import electronRequestDeclarations from '!!raw-loader!electron-request/dist/index.d.ts'
// @ts-ignore
// eslint-disable-next-line
// import queryStringDeclarations from '!!raw-loader!query-string/index'
import queryStringDeclarations from '!!raw-loader!query-string/index.d.ts'
// @ts-ignore
// eslint-disable-next-line
import nodeNetDeclarations from '!!raw-loader!@types/node/net.d.ts'
import * as monaco from 'monaco-editor';
import SavedProfile from '../profiles/SavedProfile';
import {COMMON_PROFILE_ID} from '../profiles/constants';

const initializeMonacoTypes = (isCommon: boolean) => {
const declarations = [
electronRequestDeclarations.toString()
.replace(/declare const main:.*;/g, ''),
configurationDeclarations,
];

const configDeclarationsUsable = declarations
.join('\n\n')
const configDeclarationsUsable = configurationDeclarations
.replace(/export default \w+;?/, '')
.replace(/export ([a-z]+) /g, '$1 ')
.replace(/export \{.*};/g, '');
.replace(/export \{.*};/g, '')
.replace(/export ([a-z]+) /g, '$1 ');

monaco.languages.typescript.javascriptDefaults.setExtraLibs([
{
content: nodeNetDeclarations
.replace('declare module \'net\' {', 'declare namespace net {')
.replace('declare module \'node:net\' {\n export * from \'net\';\n}', ''),
filePath: 'node/net.ts'
},
{
content: 'declare namespace queryString {\n' + (queryStringDeclarations.toString()
.replace(/export \{.*};/g, ''))
+ '\n}',
filePath: 'queryString.ts'
},
{
content: 'declare namespace ElectronRequest {\n' + (electronRequestDeclarations.toString()
.replace(/declare const main:.*;/g, '')
.replace(/export \{.*};/g, ''))
+ '\n}\n\nconst httpRequest: (requestURL: string, options?: ElectronRequest.Options) => Promise<ElectronRequest.Response>;',
filePath: 'electron-request.ts'
},
{
content: configDeclarationsUsable + `
declare const config: Configuration;
const common: object;
const memory: object;
const DefinedTranslators: DefinedTranslators;
const httpRequest: (requestURL: string, options?: Options) => Promise<Response>;
const Translators: DefinedTranslators;
const queryString: any;
`.trimEnd() + (isCommon ? '' : `
Expand Down
Loading

0 comments on commit 7aa0a9a

Please sign in to comment.