UNPKG

oda-framework

Version:

It's an ES Progressive Framework based on the technology of Web Components and designed especially for creating custom UI/UX of any complexity for web and cross-platform PWA mobile applications.

193 lines (168 loc) 7.15 kB
let allPorts = []; if (self?.onconnect === null) { self.onconnect = onconnect; } function onconnect(e) { const port = e.ports[0]; allPorts.push(port); // url = port.url; port.onmessage = onmessage.bind(port); }; async function onmessage(e) { switch (e.data?.type) { case 'init': { allPorts.push(this) structureTree ??= compressLoad(urls.map(p => p + 'structure.json')) phrases ??= compressLoad( urls.map(p => p+'phrases.json') ) dictionaries[e.data.lang] ??= loadLang(e.data.lang) } break; case 'translate': { dictionaries[e.data.lang] ??= loadLang(e.data.lang) structureTree = await structureTree phrases = await phrases dictionaries[e.data.lang] = await dictionaries[e.data.lang] // loadLang(e.data.lang) let rez = translate(e.data.key, dictionaries[e.data.lang]); structureTree = compress(structureTree, rez.structureTree) phrases = compress(phrases, rez.new) this.postMessage({ translate: rez.tr, key: e.data.key, type: 'translate', lang: e.data.lang, cast:rez.cast }); } break; case 'dictionary': { this.postMessage({ type: 'dictionary', dictionary: dictionaries[e.data.lang], phrases: phrases, structure: structureTree, lang: e.data.lang, // funTr:fn2throw(translate) }); } break; case 'update': { // dictionaries[e.data.lang] = e.data.dictionary cacheFile={} // dictionaries[e.data.lang] = undefined dictionaries[e.data.lang] = await loadLang(e.data.lang) allPorts.forEach(p => p.postMessage({ type: 'update', lang: e.data.lang })) } break; case 'update_paths': { e.data.paths.forEach(p => urls.push(p)) dictionaries = {} // phrases = undefined allPorts.forEach(p => p.postMessage({ type: 'update', lang: e.data.lang })) } break; // case 'edit_translate': { // let data = {w:{}, p:{}} // // console.log(e.data) // let d = await dictionaries[e.data.lang] || {p:{},w:{}} // if (e.data.class === 'p') { // d.p[e.data.key] = e.data.val // data.p[e.data.key] = e.data.val // } // if (e.data.class === 'w') { // d.w[e.data.key] = e.data.val // data.w[e.data.key] = e.data.val // Object.keys( structureTree?.[e.data.key] || {} ).forEach(t => { // data.p[t]=translate(t, e.data.lang) // }) // } // if (e.data.class === 'r') { // console.log('Error: no way to update RegExp') //! no way to update RegExp // } // console.log(data) // // this.postMessage({ type: 'edit_translate', w, p, lang: e.data.lang}) // allPorts.forEach(p => p.postMessage({ type: 'edit_translate', data, lang: e.data.lang})) // } break; } } async function loadLang (lang) { let fileNames = lang.split('-').map((_, i, arr) => arr.slice(0, i + 1).join('-') + '.json') let dictionaryFiles = urls.map(u => fileNames.map(fn => u + fn)).flat() let preDictionaries = compressLoad(dictionaryFiles) //preDictionaries.r = preDictionaries.r.map( ([a,b]) => [new RegExp(a),b]) //TODO : нужно отсортировать return preDictionaries } let urls = ['dictionary/']; let dictionaries = {}; let phrases; let structureTree = {} let cacheFile = {} function customLoad(x) { cacheFile[x] ??= new Promise(resolve => { let resolveSave = rez => { cacheFile[x] = rez resolve(rez) } fetch(x,{cache: "no-cache"}).then(f=> f.json().then(o => resolveSave(o)).catch(err => resolveSave({}) ) ).catch(err => resolveSave({}) ) }) return cacheFile[x] } async function compressLoad(arrPath) { let load = arrPath.map(async (file) => customLoad (file) ) return (await Promise.all(load)).reduce(compress, {}) } function compress(akk, cur) { if ((typeof akk === 'object') && (typeof cur === 'object')) { for (let k in cur) akk[k] = compress(akk[k], cur[k]) return akk } else return cur } function toRegExp ([inS, toS]) { return [new RegExp ('^' + inS.replace(/{([a-z]*)}/g,'(?<$1>.*)') + '$'), toS.replace(/{([a-z]*)}/g,'$<$1>') ] } export function translate(text, dict) { text = text.trim() // каст RegExp let regRez; for (let r of (dict.r || []) ) { regRez = text.replace(new RegExp(r[0]), r[1]) if (text!==regRez) return {tr:regRez, cast:'RegExp', regExp:r[0]} } // каст Phrases if ( !unDefined(dict.p?.[text])) return {tr:dict.p[text], cast:'Phrases'} // каст Auto (replacer нужен для игнорирования при переводе тегов) let metaInf = {cast:'Auto', ish:text, structureTree:{}, new:{w:{},p:{}} } let replacer = (_, p1, p2) => ((p1.trim() === '') ? p1 : translatePhrase(p1)) + p2 return {tr:text.replace(/([^<]*?)(<[^>]*>|$)/g, replacer), ...metaInf} // перевод фразы function translatePhrase(text) { let [result, word, test] = ['', '', 'xxx'] for (let i = 0; i < text.length; i++) { test += (text[i].toLowerCase() == text[i]) ? 'm' : 'B' test = test.slice(1) if ('abcdefghijklmnopqrstuvwxyz'.includes(text[i].toLowerCase())) { if (test == 'BBm' || test.slice(1) == 'mB') { result += translateWord(word); word = '' + text[i] } else word += text[i] } else { result += translateWord(word) + text[i]; word = '' } } if (word != '') result += translateWord(word); return result; } // перевод слова function translateWord(word) { if (word == '') return '' let key = word.toLowerCase().trim(); metaInf.structureTree[key] ??= {} if (key!==metaInf.ish.toLowerCase().trim()) { metaInf.structureTree[key][metaInf.ish] = '' metaInf.new.p[metaInf.ish] = '' } metaInf.new.w[key]='' // let test = dict.w?.[key] === undefined | dict.w?.[key] === '' let value = ( unDefined(dict.w?.[key]) ) ? word : dict.w[key] return (word.toLowerCase() == word) ? value.toLowerCase() : (word.toUpperCase() == word) ? value.toUpperCase() : value.slice(0, 1).toUpperCase() + value.slice(1).toLowerCase() } function unDefined (val) {return (val === undefined || val === '')} } function fn2throw (fn) { let str = fn.toString() let [begin, end] = ['(',')'].map(ch => str.indexOf(ch)) return [ ...str.slice(begin+1, end).split(','), str.slice(end+1) ] } // function tester () { // console.log(cacheFile) // } // console.log(self) self.tester = () => { console.log(urls) }