From 7955fc85ac089d856b44bdea78eccd26ffbd690c Mon Sep 17 00:00:00 2001 From: StefanVukovic99 Date: Mon, 3 Jun 2024 19:25:51 +0200 Subject: display inflection rule descriptions (#1000) * load descriptions in deinflector * description functions in deinflectors * show descriptions in title * use toaster * use names without internal * css lint * reformat transform descriptors * fix merge errors * done? * rename method --- ext/js/language/translator.js | 131 ++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 50 deletions(-) (limited to 'ext/js/language/translator.js') diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index e9490346..f84328d9 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -70,16 +70,16 @@ export class Translator { * @returns {Promise<{dictionaryEntries: import('dictionary').TermDictionaryEntry[], originalTextLength: number}>} An object containing dictionary entries and the length of the original source text. */ async findTerms(mode, text, options) { - const {enabledDictionaryMap, excludeDictionaryDefinitions, sortFrequencyDictionary, sortFrequencyDictionaryOrder} = options; + const {enabledDictionaryMap, excludeDictionaryDefinitions, sortFrequencyDictionary, sortFrequencyDictionaryOrder, language} = options; const tagAggregator = new TranslatorTagAggregator(); - let {dictionaryEntries, originalTextLength} = await this._findTermsInternal(text, enabledDictionaryMap, options, tagAggregator); + let {dictionaryEntries, originalTextLength} = await this._findTermsInternal(text, options, tagAggregator); switch (mode) { case 'group': dictionaryEntries = this._groupDictionaryEntriesByHeadword(dictionaryEntries, tagAggregator); break; case 'merge': - dictionaryEntries = await this._getRelatedDictionaryEntries(dictionaryEntries, options.mainDictionary, enabledDictionaryMap, tagAggregator); + dictionaryEntries = await this._getRelatedDictionaryEntries(dictionaryEntries, options, tagAggregator); break; } @@ -115,7 +115,9 @@ export class Translator { if (pronunciations.length > 1) { this._sortTermDictionaryEntrySimpleData(pronunciations); } } - return {dictionaryEntries, originalTextLength}; + const withUserFacingInflections = this._addUserFacingInflections(language, dictionaryEntries); + + return {dictionaryEntries: withUserFacingInflections, originalTextLength}; } /** @@ -206,23 +208,33 @@ export class Translator { /** * @param {string} text - * @param {Map} enabledDictionaryMap * @param {import('translation').FindTermsOptions} options * @param {TranslatorTagAggregator} tagAggregator - * @returns {Promise} + * @returns {Promise<{dictionaryEntries: import('translation-internal').TermDictionaryEntry[], originalTextLength: number}>} */ - async _findTermsInternal(text, enabledDictionaryMap, options, tagAggregator) { - if (options.removeNonJapaneseCharacters) { + async _findTermsInternal(text, options, tagAggregator) { + const {removeNonJapaneseCharacters, enabledDictionaryMap} = options; + if (removeNonJapaneseCharacters) { text = this._getJapaneseOnlyText(text); } if (text.length === 0) { return {dictionaryEntries: [], originalTextLength: 0}; } - const deinflections = await this._getDeinflections(text, enabledDictionaryMap, options); + const deinflections = await this._getDeinflections(text, options); + return this._getDictionaryEntries(deinflections, enabledDictionaryMap, tagAggregator); + } + + /** + * @param {import('translation-internal').DatabaseDeinflection[]} deinflections + * @param {import('translation').TermEnabledDictionaryMap} enabledDictionaryMap + * @param {TranslatorTagAggregator} tagAggregator + * @returns {{dictionaryEntries: import('translation-internal').TermDictionaryEntry[], originalTextLength: number}} + */ + _getDictionaryEntries(deinflections, enabledDictionaryMap, tagAggregator) { let originalTextLength = 0; - /** @type {import('dictionary').TermDictionaryEntry[]} */ + /** @type {import('translation-internal').TermDictionaryEntry[]} */ const dictionaryEntries = []; const ids = new Set(); for (const {databaseEntries, originalText, transformedText, deinflectedText, inflectionRuleChainCandidates} of deinflections) { @@ -247,19 +259,20 @@ export class Translator { ids.add(id); } } - return {dictionaryEntries, originalTextLength}; } /** - * @param {import('dictionary').TermDictionaryEntry} existingEntry - * @param {import('dictionary').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates + * @param {import('translation-internal').TermDictionaryEntry} existingEntry + * @param {import('translation-internal').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates */ _mergeInflectionRuleChains(existingEntry, inflectionRuleChainCandidates) { const existingChains = existingEntry.inflectionRuleChainCandidates; for (const {source, inflectionRules} of inflectionRuleChainCandidates) { - const duplicate = existingChains.find((existingChain) => this._areArraysEqualIgnoreOrder(existingChain.inflectionRules, inflectionRules)); + const duplicate = existingChains.find((existingChain) => { + return this._areArraysEqualIgnoreOrder(existingChain.inflectionRules, inflectionRules); + }); if (!duplicate) { existingEntry.inflectionRuleChainCandidates.push({source, inflectionRules}); } else if (duplicate.source !== source) { @@ -299,11 +312,10 @@ export class Translator { /** * @param {string} text - * @param {Map} enabledDictionaryMap * @param {import('translation').FindTermsOptions} options * @returns {Promise} */ - async _getDeinflections(text, enabledDictionaryMap, options) { + async _getDeinflections(text, options) { let deinflections = ( options.deinflect ? this._getAlgorithmDeinflections(text, options) : @@ -311,7 +323,7 @@ export class Translator { ); if (deinflections.length === 0) { return []; } - const {matchType, language} = options; + const {matchType, language, enabledDictionaryMap} = options; await this._addEntriesToDeinflections(language, deinflections, enabledDictionaryMap, matchType); @@ -455,7 +467,7 @@ export class Translator { const {trace, conditions} = deinflection; const postprocessedTextVariants = this._getTextVariants(deinflection.text, textPostprocessors, [null], sourceCache); for (const transformedText of postprocessedTextVariants) { - /** @type {import('dictionary').InflectionRuleChainCandidate} */ + /** @type {import('translation-internal').InflectionRuleChainCandidate} */ const inflectionRuleChainCandidate = { source: 'algorithm', inflectionRules: trace.map((frame) => frame.transform), @@ -577,7 +589,7 @@ export class Translator { * @param {string} transformedText * @param {string} deinflectedText * @param {number} conditions - * @param {import('dictionary').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates + * @param {import('translation-internal').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates * @returns {import('translation-internal').DatabaseDeinflection} */ _createDeinflection(originalText, transformedText, deinflectedText, conditions, inflectionRuleChainCandidates) { @@ -587,20 +599,20 @@ export class Translator { // Term dictionary entry grouping /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries - * @param {string} mainDictionary - * @param {import('translation').TermEnabledDictionaryMap} enabledDictionaryMap + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation').FindTermsOptions} options * @param {TranslatorTagAggregator} tagAggregator - * @returns {Promise} + * @returns {Promise} */ - async _getRelatedDictionaryEntries(dictionaryEntries, mainDictionary, enabledDictionaryMap, tagAggregator) { + async _getRelatedDictionaryEntries(dictionaryEntries, options, tagAggregator) { + const {mainDictionary, enabledDictionaryMap} = options; /** @type {import('translator').SequenceQuery[]} */ const sequenceList = []; - /** @type {import('translator').DictionaryEntryGroup[]} */ + /** @type {import('translation-internal').DictionaryEntryGroup[]} */ const groupedDictionaryEntries = []; - /** @type {Map} */ + /** @type {Map} */ const groupedDictionaryEntriesMap = new Map(); - /** @type {Map} */ + /** @type {Map} */ const ungroupedDictionaryEntriesMap = new Map(); for (const dictionaryEntry of dictionaryEntries) { const {definitions: [{id, dictionary, sequences: [sequence]}]} = dictionaryEntry; @@ -642,8 +654,8 @@ export class Translator { } /** - * @param {import('translator').DictionaryEntryGroup[]} groupedDictionaryEntries - * @param {Map} ungroupedDictionaryEntriesMap + * @param {import('translation-internal').DictionaryEntryGroup[]} groupedDictionaryEntries + * @param {Map} ungroupedDictionaryEntriesMap * @param {import('translator').SequenceQuery[]} sequenceList * @param {import('translation').TermEnabledDictionaryMap} enabledDictionaryMap * @param {TranslatorTagAggregator} tagAggregator @@ -664,8 +676,8 @@ export class Translator { } /** - * @param {import('translator').DictionaryEntryGroup[]} groupedDictionaryEntries - * @param {Map} ungroupedDictionaryEntriesMap + * @param {import('translation-internal').DictionaryEntryGroup[]} groupedDictionaryEntries + * @param {Map} ungroupedDictionaryEntriesMap * @param {import('translation').TermEnabledDictionaryMap} enabledDictionaryMap * @param {import('translation').TermEnabledDictionaryMap} secondarySearchDictionaryMap * @param {TranslatorTagAggregator} tagAggregator @@ -675,7 +687,7 @@ export class Translator { /** @type {import('dictionary-database').TermExactRequest[]} */ const termList = []; const targetList = []; - /** @type {Map} */ + /** @type {Map} */ const targetMap = new Map(); for (const group of groupedDictionaryEntries) { @@ -733,12 +745,12 @@ export class Translator { } /** - * @param {Iterable} dictionaryEntries + * @param {Iterable} dictionaryEntries * @param {TranslatorTagAggregator} tagAggregator - * @returns {import('dictionary').TermDictionaryEntry[]} + * @returns {import('translation-internal').TermDictionaryEntry[]} */ _groupDictionaryEntriesByHeadword(dictionaryEntries, tagAggregator) { - /** @type {Map} */ + /** @type {Map} */ const groups = new Map(); for (const dictionaryEntry of dictionaryEntries) { const {inflectionRuleChainCandidates, headwords: [{term, reading}]} = dictionaryEntry; @@ -761,7 +773,7 @@ export class Translator { // Removing data /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries * @param {Set} excludeDictionaryDefinitions */ _removeExcludedDefinitions(dictionaryEntries, excludeDictionaryDefinitions) { @@ -785,7 +797,7 @@ export class Translator { } /** - * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry + * @param {import('translation-internal').TermDictionaryEntry} dictionaryEntry */ _removeUnusedHeadwords(dictionaryEntry) { const {definitions, pronunciations, frequencies, headwords} = dictionaryEntry; @@ -1071,7 +1083,7 @@ export class Translator { // Metadata /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries * @param {import('translation').TermEnabledDictionaryMap} enabledDictionaryMap * @param {TranslatorTagAggregator} tagAggregator */ @@ -1543,7 +1555,7 @@ export class Translator { /** * @param {boolean} isPrimary - * @param {import('dictionary').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates + * @param {import('translation-internal').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates * @param {number} score * @param {number} dictionaryIndex * @param {number} dictionaryPriority @@ -1551,7 +1563,7 @@ export class Translator { * @param {number} maxOriginalTextLength * @param {import('dictionary').TermHeadword[]} headwords * @param {import('dictionary').TermDefinition[]} definitions - * @returns {import('dictionary').TermDictionaryEntry} + * @returns {import('translation-internal').TermDictionaryEntry} */ _createTermDictionaryEntry(isPrimary, inflectionRuleChainCandidates, score, dictionaryIndex, dictionaryPriority, sourceTermExactMatchCount, maxOriginalTextLength, headwords, definitions) { return { @@ -1576,11 +1588,11 @@ export class Translator { * @param {string} originalText * @param {string} transformedText * @param {string} deinflectedText - * @param {import('dictionary').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates + * @param {import('translation-internal').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates * @param {boolean} isPrimary * @param {Map} enabledDictionaryMap * @param {TranslatorTagAggregator} tagAggregator - * @returns {import('dictionary').TermDictionaryEntry} + * @returns {import('translation-internal').TermDictionaryEntry} */ _createTermDictionaryEntryFromDatabaseEntry(databaseEntry, originalText, transformedText, deinflectedText, inflectionRuleChainCandidates, isPrimary, enabledDictionaryMap, tagAggregator) { const { @@ -1628,10 +1640,10 @@ export class Translator { } /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries * @param {boolean} checkDuplicateDefinitions * @param {TranslatorTagAggregator} tagAggregator - * @returns {import('dictionary').TermDictionaryEntry} + * @returns {import('translation-internal').TermDictionaryEntry} */ _createGroupedDictionaryEntry(dictionaryEntries, checkDuplicateDefinitions, tagAggregator) { // Headwords are generated before sorting, so that the order of dictionaryEntries can be maintained @@ -1864,13 +1876,13 @@ export class Translator { } /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries */ _sortTermDictionaryEntries(dictionaryEntries) { const stringComparer = this._stringComparer; /** - * @param {import('dictionary').TermDictionaryEntry} v1 - * @param {import('dictionary').TermDictionaryEntry} v2 + * @param {import('translation-internal').TermDictionaryEntry} v1 + * @param {import('translation-internal').TermDictionaryEntry} v2 * @returns {number} */ const compareFunction = (v1, v2) => { @@ -1968,7 +1980,7 @@ export class Translator { } /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries */ _sortTermDictionaryEntriesById(dictionaryEntries) { if (dictionaryEntries.length <= 1) { return; } @@ -2033,7 +2045,7 @@ export class Translator { } /** - * @param {import('dictionary').TermDictionaryEntry[]} dictionaryEntries + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries * @param {string} dictionary * @param {boolean} ascending */ @@ -2078,7 +2090,7 @@ export class Translator { } /** - * @param {import('dictionary').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates + * @param {import('translation-internal').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates * @returns {number} */ _getShortestInflectionChainLength(inflectionRuleChainCandidates) { @@ -2090,6 +2102,25 @@ export class Translator { return length; } + + /** + * @param {string} language + * @param {import('translation-internal').TermDictionaryEntry[]} dictionaryEntries + * @returns {import('dictionary').TermDictionaryEntry[]} + */ + _addUserFacingInflections(language, dictionaryEntries) { + const result = []; + for (const dictionaryEntry of dictionaryEntries) { + const {inflectionRuleChainCandidates} = dictionaryEntry; + const expandedChains = inflectionRuleChainCandidates.map(({source, inflectionRules}) => ({ + source, + inflectionRules: this._multiLanguageTransformer.getUserFacingInflectionRules(language, inflectionRules), + })); + result.push({...dictionaryEntry, inflectionRuleChainCandidates: expandedChains}); + } + return result; + } + // Miscellaneous /** -- cgit v1.2.3