Skip to content

Commit

Permalink
Dictionary deinflections (#503)
Browse files Browse the repository at this point in the history
* wip

* wip

* fix v3

* wip

* fix tests

* fix maxitems

* hide deinflection definitions

* fix anki template

* undo unnecessary change

* delete console.log

* refactor

* add set false to handlebars

* lint

* fix tests

* fix comments

* fix

* use Map in areArraysEqualIgnoreOrder

* move inflection source icons to css

* lint

* improve naming

* fix tests

* add test

* typescript

* use for of

* wip

* comments

* anki template upgrade

* update descriptions
  • Loading branch information
StefanVukovic99 authored Jan 20, 2024
1 parent 48f1d01 commit 2b87c91
Show file tree
Hide file tree
Showing 29 changed files with 1,861 additions and 342 deletions.
30 changes: 26 additions & 4 deletions ext/css/display.css
Original file line number Diff line number Diff line change
Expand Up @@ -809,17 +809,39 @@ button.action-button:active {


/* Inflections */
.inflection-list {
display: inline-block;
.inflection-rule-chains {
padding-inline-start: 0;
list-style-type: none;
}
.inflection-rule-chain {
color: var(--reason-text-color);
}
.inflection-list:empty {
.inflection-rule-chain:empty {
display: none;
}
.inflection-list>.inflection+.inflection-separator+.inflection::before {
.inflection-rule-chain>.inflection+.inflection-separator+.inflection::before {
content: var(--inflection-separator);
padding: 0 0.25em;
}
.inflection-source-icon {
display: inline-block;
white-space: nowrap;
text-align: center;
width: 1.4em;
margin-right: 0.2em;
}
.inflection-source-icon[data-inflection-source='dictionary']::after {
content: '📖';
}
.inflection-source-icon[data-inflection-source='algorithm']::after {
content: '🧩';
}
.inflection-source-icon[data-inflection-source='both'] {
width: 2.8em;
}
.inflection-source-icon[data-inflection-source='both']::after {
content: '🧩📖';
}


/* Headwords */
Expand Down
20 changes: 19 additions & 1 deletion ext/data/schemas/dictionary-term-bank-v3-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@
},
{
"type": "string",
"description": "String of space-separated rule identifiers for the definition which is used to validate delinflection. Valid rule identifiers are: v1: ichidan verb; v5: godan verb; vs: suru verb; vk: kuru verb; adj-i: i-adjective. An empty string corresponds to words which aren't inflected, such as nouns."
"description": "String of space-separated rule identifiers for the definition which is used to validate deinflection. An empty string should be used for words which aren't inflected."
},
{
"type": "number",
Expand Down Expand Up @@ -535,6 +535,24 @@
}
}
]
},
{
"type": "array",
"description": "Deinflection of the term to an uninflected term.",
"items": [
{
"type": "string",
"description": "The uninflected term."
},
{
"type": "array",
"description": "A chain of inflection rules that produced the inflected term",
"items": {
"type": "string",
"description": "A single inflection rule."
}
}
]
}
]
}
Expand Down
7 changes: 6 additions & 1 deletion ext/data/schemas/options-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,8 @@
"enabled",
"allowSecondarySearches",
"definitionsCollapsible",
"partsOfSpeechFilter"
"partsOfSpeechFilter",
"useDeinflections"
],
"properties": {
"name": {
Expand All @@ -850,6 +851,10 @@
"partsOfSpeechFilter": {
"type": "boolean",
"default": true
},
"useDeinflections": {
"type": "boolean",
"default": true
}
}
}
Expand Down
52 changes: 52 additions & 0 deletions ext/data/templates/anki-field-templates-upgrade-v24.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{{#*inline "phonetic-transcriptions"}}
{{~#if (op ">" definition.phoneticTranscriptions.length 0)~}}
<ul>
{{~#each definition.phoneticTranscriptions~}}
{{~#each phoneticTranscriptions~}}
<li>
{{~set "any" false~}}
{{~#each tags~}}
{{~#if (get "any")}}, {{else}}<i>({{/if~}}
{{name}}
{{~set "any" true~}}
{{~/each~}}
{{~#if (get "any")}})</i> {{/if~}}
{{ipa~}}
</li>
{{~/each~}}
{{~/each~}}
</ul>
{{~/if~}}
{{/inline}}

{{<<<<<<<}}
{{#*inline "conjugation"}}
{{~#if (op ">" definition.inflectionRuleChainCandidates.length 0)~}}
{{~set "multiple" false~}}
{{~#if (op ">" definition.inflectionRuleChainCandidates.length 1)~}}
{{~set "multiple" true~}}
{{~/if~}}
{{~#if (get "multiple")~}}<ul>{{/if~}}
{{~#each definition.inflectionRuleChainCandidates~}}
{{~#if (op ">" inflectionRules.length 0)~}}
{{~#if (get "multiple")~}}<li>{{/if~}}
{{~#each inflectionRules~}}
{{~#if (op ">" @index 0)}} « {{/if~}}
{{.}}
{{~/each~}}
{{~#if (get "multiple")~}}</li>{{/if~}}
{{~/if~}}
{{~/each~}}
{{~#if (get "multiple")~}}</ul>{{/if~}}
{{~/if~}}
{{/inline}}
{{=======}}
{{#*inline "conjugation"}}
{{~#if definition.reasons~}}
{{~#each definition.reasons~}}
{{~#if (op ">" @index 0)}} « {{/if~}}
{{.}}
{{~/each~}}
{{~/if~}}
{{/inline}}
{{>>>>>>>>}}
22 changes: 17 additions & 5 deletions ext/data/templates/default-anki-field-templates.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,23 @@
{{/inline}}

{{#*inline "conjugation"}}
{{~#if definition.reasons~}}
{{~#each definition.reasons~}}
{{~#if (op ">" @index 0)}} « {{/if~}}
{{.}}
{{~/each~}}
{{~#if (op ">" definition.inflectionRuleChainCandidates.length 0)~}}
{{~set "multiple" false~}}
{{~#if (op ">" definition.inflectionRuleChainCandidates.length 1)~}}
{{~set "multiple" true~}}
{{~/if~}}
{{~#if (get "multiple")~}}<ul>{{/if~}}
{{~#each definition.inflectionRuleChainCandidates~}}
{{~#if (op ">" inflectionRules.length 0)~}}
{{~#if (get "multiple")~}}<li>{{/if~}}
{{~#each inflectionRules~}}
{{~#if (op ">" @index 0)}} « {{/if~}}
{{.}}
{{~/each~}}
{{~#if (get "multiple")~}}</li>{{/if~}}
{{~/if~}}
{{~/each~}}
{{~#if (get "multiple")~}}</ul>{{/if~}}
{{~/if~}}
{{/inline}}

Expand Down
3 changes: 2 additions & 1 deletion ext/display-templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<div class="headword-list"></div>
<div class="headword-list-details">
<div class="headword-list-tag-list tag-list"></div>
<div class="inflection-list"></div>
<ul class="inflection-rule-chains"></ul>
</div>
</div>
<div class="entry-body">
Expand Down Expand Up @@ -77,6 +77,7 @@
<template id="definition-disambiguation-template"><span class="definition-disambiguation"></span></template>
<template id="gloss-item-template"><li class="gloss-item click-scannable"><span class="gloss-separator"> </span><span class="gloss-content"></span></li></template>
<template id="gloss-item-image-description-template"> <span class="gloss-image-description"></span></template>
<template id="inflection-rule-chain-template"><li class="inflection-rule-chain"></li></template>
<template id="inflection-template"><span class="inflection"></span><span class="inflection-separator"> </span></template>

<!-- Frequency templates -->
Expand Down
8 changes: 5 additions & 3 deletions ext/js/background/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -2428,7 +2428,8 @@ export class Backend {
index: enabledDictionaryMap.size,
priority: 0,
allowSecondarySearches: false,
partsOfSpeechFilter: true
partsOfSpeechFilter: true,
useDeinflections: true
});
excludeDictionaryDefinitions = new Set();
excludeDictionaryDefinitions.add(mainDictionary);
Expand Down Expand Up @@ -2474,12 +2475,13 @@ export class Backend {
const enabledDictionaryMap = new Map();
for (const dictionary of options.dictionaries) {
if (!dictionary.enabled) { continue; }
const {name, priority, allowSecondarySearches, partsOfSpeechFilter} = dictionary;
const {name, priority, allowSecondarySearches, partsOfSpeechFilter, useDeinflections} = dictionary;
enabledDictionaryMap.set(name, {
index: enabledDictionaryMap.size,
priority,
allowSecondarySearches,
partsOfSpeechFilter
partsOfSpeechFilter,
useDeinflections
});
}
return enabledDictionaryMap;
Expand Down
17 changes: 16 additions & 1 deletion ext/js/data/options-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,8 @@ export class OptionsUtil {
this._updateVersion20,
this._updateVersion21,
this._updateVersion22,
this._updateVersion23
this._updateVersion23,
this._updateVersion24
];
if (typeof targetVersion === 'number' && targetVersion < result.length) {
result.splice(targetVersion);
Expand Down Expand Up @@ -1155,6 +1156,20 @@ export class OptionsUtil {
}
}

/**
* - Added dictionaries[].useDeinflections.
* @type {import('options-util').UpdateFunction}
*/
async _updateVersion24(options) {
await this._applyAnkiFieldTemplatesPatch(options, '/data/templates/anki-field-templates-upgrade-v24.handlebars');

for (const {options: profileOptions} of options.profiles) {
for (const dictionary of profileOptions.dictionaries) {
dictionary.useDeinflections = true;
}
}
}

/**
* @param {string} url
* @returns {Promise<chrome.tabs.Tab>}
Expand Down
4 changes: 2 additions & 2 deletions ext/js/data/sandbox/anki-note-data-creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ export class AnkiNoteDataCreator {
case 'merge': type = 'termMerged'; break;
}

const {inflections, score, dictionaryIndex, dictionaryPriority, sourceTermExactMatchCount, definitions} = dictionaryEntry;
const {inflectionRuleChainCandidates, score, dictionaryIndex, dictionaryPriority, sourceTermExactMatchCount, definitions} = dictionaryEntry;

let {url} = context;
if (typeof url !== 'string') { url = ''; }
Expand All @@ -401,7 +401,7 @@ export class AnkiNoteDataCreator {
source: (primarySource !== null ? primarySource.transformedText : null),
rawSource: (primarySource !== null ? primarySource.originalText : null),
sourceTerm: (type !== 'termMerged' ? (primarySource !== null ? primarySource.deinflectedText : null) : void 0),
reasons: inflections,
inflectionRuleChainCandidates,
score,
isPrimary: (type === 'term' ? dictionaryEntry.isPrimary : void 0),
get sequence() { return self.getCachedValue(sequence); },
Expand Down
2 changes: 1 addition & 1 deletion ext/js/dictionary/dictionary-importer.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export class DictionaryImporter {
const glossaryList = entry.glossary;
for (let j = 0, jj = glossaryList.length; j < jj; ++j) {
const glossary = glossaryList[j];
if (typeof glossary !== 'object' || glossary === null) { continue; }
if (typeof glossary !== 'object' || glossary === null || Array.isArray(glossary)) { continue; }
glossaryList[j] = this._formatDictionaryTermGlossaryObject(glossary, entry, requirements);
}
if ((i % formatProgressInterval) === 0) {
Expand Down
46 changes: 42 additions & 4 deletions ext/js/display/display-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export class DisplayGenerator {
const node = this._instantiate('term-entry');

const headwordsContainer = this._querySelector(node, '.headword-list');
const inflectionsContainer = this._querySelector(node, '.inflection-list');
const inflectionRuleChainsContainer = this._querySelector(node, '.inflection-rule-chains');
const groupedPronunciationsContainer = this._querySelector(node, '.pronunciation-group-list');
const frequencyGroupListContainer = this._querySelector(node, '.frequency-group-list');
const definitionsContainer = this._querySelector(node, '.definition-list');
const headwordTagsContainer = this._querySelector(node, '.headword-list-tag-list');

const {headwords, type, inflections, definitions, frequencies, pronunciations} = dictionaryEntry;
const {headwords, type, inflectionRuleChainCandidates, definitions, frequencies, pronunciations} = dictionaryEntry;
const groupedPronunciations = DictionaryDataUtil.getGroupedPronunciations(dictionaryEntry);
const pronunciationCount = groupedPronunciations.reduce((i, v) => i + v.pronunciations.length, 0);
const groupedFrequencies = DictionaryDataUtil.groupTermFrequencies(dictionaryEntry);
Expand Down Expand Up @@ -112,7 +112,7 @@ export class DisplayGenerator {
}
headwordsContainer.dataset.count = `${headwords.length}`;

this._appendMultiple(inflectionsContainer, this._createTermInflection.bind(this), inflections);
this._appendMultiple(inflectionRuleChainsContainer, this._createInflectionRuleChain.bind(this), inflectionRuleChainCandidates);
this._appendMultiple(frequencyGroupListContainer, this._createFrequencyGroup.bind(this), groupedFrequencies, false);
this._appendMultiple(groupedPronunciationsContainer, this._createGroupedPronunciation.bind(this), groupedPronunciations);
this._appendMultiple(headwordTagsContainer, this._createTermTag.bind(this), termTags, headwords.length);
Expand Down Expand Up @@ -356,6 +356,44 @@ export class DisplayGenerator {
return node;
}

/**
* @param {import('dictionary').InflectionRuleChainCandidate} inflectionRuleChain
* @returns {?HTMLElement}
*/
_createInflectionRuleChain(inflectionRuleChain) {
const {source, inflectionRules} = inflectionRuleChain;
if (!Array.isArray(inflectionRules) || inflectionRules.length === 0) { return null; }
const fragment = this._instantiate('inflection-rule-chain');

const sourceIcon = this._getInflectionSourceIcon(source);

fragment.appendChild(sourceIcon);

this._appendMultiple(fragment, this._createTermInflection.bind(this), inflectionRules);
return fragment;
}

/**
* @param {import('dictionary').InflectionSource} source
* @returns {HTMLElement}
*/
_getInflectionSourceIcon(source) {
const icon = document.createElement('span');
icon.classList.add('inflection-source-icon');
icon.dataset.inflectionSource = source;
switch (source) {
case 'dictionary':
icon.title = 'Dictionary Deinflection';
return icon;
case 'algorithm':
icon.title = 'Algorithm Deinflection';
return icon;
case 'both':
icon.title = 'Dictionary and Algorithm Deinflection';
return icon;
}
}

/**
* @param {string} inflection
* @returns {DocumentFragment}
Expand Down Expand Up @@ -396,7 +434,7 @@ export class DisplayGenerator {
}

/**
* @param {import('dictionary-data').TermGlossary} entry
* @param {import('dictionary-data').TermGlossaryContent} entry
* @param {string} dictionary
* @returns {?HTMLElement}
*/
Expand Down
2 changes: 1 addition & 1 deletion ext/js/language/deinflector.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class Deinflector {
/**
* @param {string} term
* @param {import('translation-internal').DeinflectionRuleFlags} rules
* @param {string[]} reasons
* @param {import('dictionary').InflectionRuleChain} reasons
* @returns {import('translation-internal').Deinflection}
*/
_createDeinflection(term, rules, reasons) {
Expand Down
Loading

0 comments on commit 2b87c91

Please sign in to comment.