diff options
Diffstat (limited to 'ext/bg/js/translator.js')
-rw-r--r-- | ext/bg/js/translator.js | 294 |
1 files changed, 151 insertions, 143 deletions
diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index fd414847..e534e0cb 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -25,171 +25,199 @@ class Translator { this.deinflector = new Deinflector(); } - loadData({loadEnamDict=true}, callback) { + loadData(callback) { if (this.loaded) { - callback(); - return; + return Promise.resolve(); } - Translator.loadData('bg/data/rules.json') - .then((response) => { - this.deinflector.setRules(JSON.parse(response)); - return Translator.loadData('bg/data/tags.json'); - }) - .then((response) => { - this.tagMeta = JSON.parse(response); - return Translator.loadData('bg/data/edict.json'); - }) - .then((response) => { - this.dictionary.addTermDict('edict', JSON.parse(response)); - return Translator.loadData('bg/data/kanjidic.json'); - }) - .then((response) => { - this.dictionary.addKanjiDict('kanjidic', JSON.parse(response)); - return loadEnamDict ? Translator.loadData('bg/data/enamdict.json') : Promise.resolve(null); - }) - .then((response) => { - if (response !== null) { - this.dictionary.addTermDict('enamdict', JSON.parse(response)); + return loadJson('bg/data/rules.json').then(rules => { + this.deinflector.setRules(rules); + return loadJson('bg/data/tags.json'); + }).then(tagMeta => { + this.tagMeta = tagMeta; + return this.dictionary.prepareDb(); + }).then(exists => { + if (exists) { + return; + } + + if (callback) { + callback({state: 'begin', progress: 0}); + } + + const banks = {}; + const bankCallback = (loaded, total, indexUrl) => { + banks[indexUrl] = {loaded, total}; + + let percent = 0.0; + for (const url in banks) { + percent += banks[url].loaded / banks[url].total; } - this.loaded = true; - callback(); - }); - } + percent /= 3.0; - findTerm(text) { - const groups = {}; - for (let i = text.length; i > 0; --i) { - const term = text.slice(0, i); - const dfs = this.deinflector.deinflect(term, t => { - const tags = []; - for (const d of this.dictionary.findTerm(t)) { - tags.push(d.tags); + if (callback) { + callback({state: 'update', progress: Math.ceil(100.0 * percent)}); } + }; - return tags; + return Promise.all([ + this.dictionary.importTermDict('bg/data/edict/index.json', bankCallback), + this.dictionary.importTermDict('bg/data/enamdict/index.json', bankCallback), + this.dictionary.importKanjiDict('bg/data/kanjidic/index.json', bankCallback), + ]).then(() => { + return this.dictionary.sealDb(); + }).then(() => { + if (callback) { + callback({state: 'end', progress: 100.0}); + } }); + }).then(() => { + this.loaded = true; + }); + } - if (dfs === null) { - continue; - } + findTermGroups(text) { + const deinflectGroups = {}; + const deinflectPromises = []; - for (const df of dfs) { - this.processTerm(groups, df.source, df.tags, df.rules, df.root); - } + for (let i = text.length; i > 0; --i) { + deinflectPromises.push( + this.deinflector.deinflect(text.slice(0, i), term => { + return this.dictionary.findTerm(term).then(definitions => definitions.map(definition => definition.tags)); + }).then(deinflects => { + const processPromises = []; + for (const deinflect of deinflects) { + processPromises.push(this.processTerm( + deinflectGroups, + deinflect.source, + deinflect.tags, + deinflect.rules, + deinflect.root + )); + } + + return Promise.all(processPromises); + }) + ); } - let definitions = []; - for (const key in groups) { - definitions.push(groups[key]); - } + return Promise.all(deinflectPromises).then(() => deinflectGroups); + } - definitions = definitions.sort((v1, v2) => { - const sl1 = v1.source.length; - const sl2 = v2.source.length; - if (sl1 > sl2) { - return -1; - } else if (sl1 < sl2) { - return 1; + findTerm(text) { + return this.findTermGroups(text).then(deinflectGroups => { + let definitions = []; + for (const key in deinflectGroups) { + definitions.push(deinflectGroups[key]); } - const s1 = v1.score; - const s2 = v2.score; - if (s1 > s2) { - return -1; - } else if (s1 < s2) { - return 1; - } + definitions = definitions.sort((v1, v2) => { + const sl1 = v1.source.length; + const sl2 = v2.source.length; + if (sl1 > sl2) { + return -1; + } else if (sl1 < sl2) { + return 1; + } - const rl1 = v1.rules.length; - const rl2 = v2.rules.length; - if (rl1 < rl2) { - return -1; - } else if (rl1 > rl2) { - return 1; - } + const s1 = v1.score; + const s2 = v2.score; + if (s1 > s2) { + return -1; + } else if (s1 < s2) { + return 1; + } - return v2.expression.localeCompare(v1.expression); - }); + const rl1 = v1.rules.length; + const rl2 = v2.rules.length; + if (rl1 < rl2) { + return -1; + } else if (rl1 > rl2) { + return 1; + } - let length = 0; - for (const result of definitions) { - length = Math.max(length, result.source.length); - } + return v2.expression.localeCompare(v1.expression); + }); + + let length = 0; + for (const result of definitions) { + length = Math.max(length, result.source.length); + } - return {definitions: definitions, length: length}; + return {definitions, length}; + }); } findKanji(text) { - let definitions = []; const processed = {}; + const promises = []; for (const c of text) { if (!processed[c]) { - definitions = definitions.concat(this.dictionary.findKanji(c)); + promises.push(this.dictionary.findKanji(c).then((definitions) => definitions)); processed[c] = true; } } - return this.processKanji(definitions); + return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b)))); } processTerm(groups, source, tags, rules, root) { - for (const entry of this.dictionary.findTerm(root)) { - if (entry.id in groups) { - continue; - } + return this.dictionary.findTerm(root).then(definitions => { + for (const definition of definitions) { + if (definition.id in groups) { + continue; + } - let matched = tags.length === 0; - for (const tag of tags) { - if (entry.tags.indexOf(tag) !== -1) { - matched = true; - break; + let matched = tags.length === 0; + for (const tag of tags) { + if (definition.tags.includes(tag)) { + matched = true; + break; + } } - } - if (!matched) { - continue; - } + if (!matched) { + continue; + } - const tagItems = []; - for (const tag of entry.tags) { - const tagItem = { - name: tag, - class: 'default', - order: Number.MAX_SAFE_INTEGER, - score: 0, - desc: entry.entities[tag] || '', - }; + const tagItems = []; + for (const tag of definition.tags) { + const tagItem = { + name: tag, + class: 'default', + order: Number.MAX_SAFE_INTEGER, + score: 0, + desc: definition.entities[tag] || '', + }; + + this.applyTagMeta(tagItem); + tagItems.push(tagItem); + } - this.applyTagMeta(tagItem); - tagItems.push(tagItem); - } + let score = 0; + for (const tagItem of tagItems) { + score += tagItem.score; + } - let score = 0; - for (const tagItem of tagItems) { - score += tagItem.score; + groups[definition.id] = { + score, + source, + rules, + expression: definition.expression, + reading: definition.reading, + glossary: definition.glossary, + tags: Translator.sortTags(tagItems) + }; } - - groups[entry.id] = { - score, - source, - rules, - expression: entry.expression, - reading: entry.reading, - glossary: entry.glossary, - tags: Translator.sortTags(tagItems) - }; - } + }); } - processKanji(entries) { - const results = []; - - for (const entry of entries) { + processKanji(definitions) { + for (const definition of definitions) { const tagItems = []; - for (const tag of entry.tags) { + for (const tag of definition.tags) { const tagItem = { name: tag, class: 'default', @@ -201,16 +229,10 @@ class Translator { tagItems.push(tagItem); } - results.push({ - character: entry.character, - kunyomi: entry.kunyomi, - onyomi: entry.onyomi, - glossary: entry.glossary, - tags: Translator.sortTags(tagItems) - }); + definition.tags = Translator.sortTags(tagItems); } - return results; + return definitions; } applyTagMeta(tag) { @@ -241,18 +263,4 @@ class Translator { return 0; }); } - - static isKanji(c) { - const code = c.charCodeAt(0); - return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; - } - - static loadData(url) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.addEventListener('load', () => resolve(xhr.responseText)); - xhr.open('GET', chrome.extension.getURL(url), true); - xhr.send(); - }); - } } |