Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mololab
GitHub Repository: mololab/json-translator
Path: blob/master/src/core/translator.ts
235 views
1
import {
2
getLanguageVariant,
3
getTranslationModuleByKey,
4
translationModuleKeys,
5
} from '../modules/helpers';
6
import {TranslationConfig} from '../modules/modules';
7
import { warn } from '../utils/console';
8
import { default_value } from '../utils/micro';
9
import * as ignorer from './ignorer';
10
import * as crypto from 'crypto';
11
12
13
export function getKey(str: string, from: string, to: string):string {
14
let strKey = crypto.createHash('md5').update(str).digest('hex')
15
return `${from}-${to}-${strKey}`;
16
}
17
18
export function translateCacheModule(fallbackFn: Function, cacheObject: Record<string, any>, onSuccess: Function){
19
return async (str: string, from: string, to: string): Promise<string> => {
20
let key = getKey(str, from, to);
21
if (cacheObject[key] !== undefined && cacheObject[key] !== default_value) {
22
onSuccess(true);
23
return Promise.resolve(cacheObject[key]);
24
} else {
25
return fallbackFn(str, from, to);
26
}
27
};
28
}
29
30
export async function plaintranslate(
31
TranslationConfig: TranslationConfig,
32
str: string,
33
from: string,
34
to: string,
35
skipModuleKeys: string[],
36
cacheObject?: Record<string, any>
37
): Promise<string> {
38
// Check for empty strings and return immediately if empty
39
if (str.trim() === '') return str;
40
41
// step: map the subset of string need to be ignored
42
let {
43
word: ignored_str,
44
double_brackets_map,
45
single_brackets_map,
46
} = ignorer.map(str);
47
48
// step: translate in try-catch to keep continuity
49
try {
50
// step: translate with proper source
51
let defaultTranslateModule: Function = TranslationConfig.TranslationModule.translate
52
let moduleOrCache = TranslationConfig.cacheEnabled ? translateCacheModule(defaultTranslateModule, cacheObject || {}, ()=> {
53
global.skipInCache = global.skipInCache + 1;
54
}) : defaultTranslateModule
55
56
let translatedStr = await moduleOrCache(
57
ignored_str,
58
from,
59
to
60
);
61
62
// step: put ignored values back
63
translatedStr = ignorer.unMap(
64
translatedStr,
65
double_brackets_map,
66
single_brackets_map
67
);
68
69
global.totalTranslated = global.totalTranslated + 1;
70
71
return translatedStr;
72
} catch (e) {
73
// error case
74
console.log(e)
75
const clonedTranslationConfig = Object.assign({}, TranslationConfig); // cloning to escape ref value
76
const clonedSkipModuleKeys = Object.assign([], skipModuleKeys); // cloning to escape ref value
77
78
clonedSkipModuleKeys.push(clonedTranslationConfig.moduleKey);
79
80
const {
81
newModuleKey,
82
newFrom,
83
newTo,
84
skippedModuleKeys,
85
} = newTranslationModule(
86
clonedTranslationConfig.moduleKey,
87
clonedSkipModuleKeys,
88
from,
89
to
90
);
91
92
// add skippedModuleKeys to general skipModuleKeys
93
skippedModuleKeys.forEach(skippedModuleKey => {
94
clonedSkipModuleKeys.push(skippedModuleKey);
95
});
96
97
let stop: boolean =
98
!clonedTranslationConfig.fallback || newModuleKey === undefined;
99
100
if (stop) {
101
warn(
102
`\nerror while translating "${str}" using ${clonedTranslationConfig.moduleKey}. Assigned "--" instead of exit from cli.`
103
);
104
105
global.totalTranslated = global.totalTranslated + 1;
106
107
return default_value;
108
}
109
110
warn(
111
`\nerror while translating "${str}" using ${clonedTranslationConfig.moduleKey}. Tried: ${clonedSkipModuleKeys}. Trying ${newModuleKey}.`
112
);
113
114
// update the TranslationModule for next try
115
clonedTranslationConfig.TranslationModule = getTranslationModuleByKey(
116
newModuleKey as string
117
);
118
clonedTranslationConfig.moduleKey = newModuleKey as string;
119
120
return plaintranslate(
121
clonedTranslationConfig,
122
str,
123
newFrom as string,
124
newTo as string,
125
clonedSkipModuleKeys
126
);
127
}
128
}
129
130
function newTranslationModule(
131
sourceModuleKeys: string,
132
skipModuleKeys: string[],
133
from: string,
134
to: string
135
) {
136
const default_data = {
137
newModuleKey: undefined,
138
newFrom: undefined,
139
newTo: undefined,
140
skippedModuleKeys: [],
141
};
142
const skippedModuleKeys: string[] = [];
143
144
const allModuleKeys: string[] = translationModuleKeys();
145
const result: string[] = allModuleKeys.filter(
146
item => !skipModuleKeys.includes(item)
147
);
148
149
if (result.length == 0) {
150
return default_data;
151
}
152
153
for (let i = 0; i < result.length; i++) {
154
let newModuleKey = result[i];
155
156
let newFrom = getLanguageVariant(sourceModuleKeys, from, newModuleKey);
157
let newTo = getLanguageVariant(sourceModuleKeys, to, newModuleKey);
158
159
// if found valid newFrom & newTo, return
160
if (newFrom && newTo) {
161
return {
162
newModuleKey,
163
newFrom,
164
newTo,
165
skippedModuleKeys,
166
};
167
}
168
// otherwise skip to next module, add key to skippedModuleKeys
169
else {
170
skippedModuleKeys.push(newModuleKey);
171
}
172
}
173
174
// has valid newModuleKey & from & to
175
default_data.skippedModuleKeys = skippedModuleKeys as any;
176
return default_data;
177
}
178
179