diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2021-03-26 19:50:54 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-26 19:50:54 -0400 |
commit | 90f7d5ba07340413aa7e43c3a0cc038690b32db3 (patch) | |
tree | b3c57f9240de2e3a86cbc8dba5fe93d71e4067ae /ext | |
parent | 482dd8c8d8339d29c9e7a202cbf4c54bf7cf291d (diff) |
Add part of speech info (#1561)
* Add part of speech info to headwords
* Expose parts of speech to Anki template rendering
* Expose parts of speech
* Update pitch accent categories
* Update docs
* Add part-of-speech
* Update options and tests
* Update markers
* Update test data
Diffstat (limited to 'ext')
-rw-r--r-- | ext/data/templates/anki-field-templates-upgrade-v10.handlebars | 30 | ||||
-rw-r--r-- | ext/data/templates/default-anki-field-templates.handlebars | 31 | ||||
-rw-r--r-- | ext/js/data/anki-note-data-creator.js | 5 | ||||
-rw-r--r-- | ext/js/data/options-util.js | 6 | ||||
-rw-r--r-- | ext/js/display/display-generator.js | 26 | ||||
-rw-r--r-- | ext/js/language/translator.js | 13 | ||||
-rw-r--r-- | ext/js/pages/settings/anki-controller.js | 1 | ||||
-rw-r--r-- | ext/settings.html | 4 |
8 files changed, 103 insertions, 13 deletions
diff --git a/ext/data/templates/anki-field-templates-upgrade-v10.handlebars b/ext/data/templates/anki-field-templates-upgrade-v10.handlebars new file mode 100644 index 00000000..8442a93c --- /dev/null +++ b/ext/data/templates/anki-field-templates-upgrade-v10.handlebars @@ -0,0 +1,30 @@ +{{#*inline "part-of-speech-pretty"}} + {{~#if (op "===" . "v1")~}}Ichidan verb + {{~else if (op "===" . "v5")~}}Godan verb + {{~else if (op "===" . "vk")~}}Kuru verb + {{~else if (op "===" . "vs")~}}Suru verb + {{~else if (op "===" . "vz")~}}Zuru verb + {{~else if (op "===" . "adj-i")~}}I-adjective + {{~else if (op "===" . "n")~}}Noun + {{~else~}}{{.}} + {{~/if~}} +{{/inline}} + +{{#*inline "part-of-speech"}} + {{~#scope~}} + {{~#if (op "!==" definition.type "kanji")~}} + {{~#set "first" true}}{{/set~}} + {{~#each definition.expressions~}} + {{~#each wordClasses~}} + {{~#unless (get (concat "used_" .))~}} + {{~> part-of-speech-pretty . ~}} + {{~#unless (get "first")}}, {{/unless~}} + {{~#set (concat "used_" .) true~}}{{~/set~}} + {{~#set "first" false~}}{{~/set~}} + {{~/unless~}} + {{~/each~}} + {{~/each~}} + {{~#if (get "first")~}}Unknown{{~/if~}} + {{~/if~}} + {{~/scope~}} +{{/inline}} diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 0f390e8d..ec57a826 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -341,4 +341,35 @@ {{~/scope~}} {{/inline}} +{{#*inline "part-of-speech-pretty"}} + {{~#if (op "===" . "v1")~}}Ichidan verb + {{~else if (op "===" . "v5")~}}Godan verb + {{~else if (op "===" . "vk")~}}Kuru verb + {{~else if (op "===" . "vs")~}}Suru verb + {{~else if (op "===" . "vz")~}}Zuru verb + {{~else if (op "===" . "adj-i")~}}I-adjective + {{~else if (op "===" . "n")~}}Noun + {{~else~}}{{.}} + {{~/if~}} +{{/inline}} + +{{#*inline "part-of-speech"}} + {{~#scope~}} + {{~#if (op "!==" definition.type "kanji")~}} + {{~#set "first" true}}{{/set~}} + {{~#each definition.expressions~}} + {{~#each wordClasses~}} + {{~#unless (get (concat "used_" .))~}} + {{~> part-of-speech-pretty . ~}} + {{~#unless (get "first")}}, {{/unless~}} + {{~#set (concat "used_" .) true~}}{{~/set~}} + {{~#set "first" false~}}{{~/set~}} + {{~/unless~}} + {{~/each~}} + {{~/each~}} + {{~#if (get "first")~}}Unknown{{~/if~}} + {{~/if~}} + {{~/scope~}} +{{/inline}} + {{~> (lookup . "marker") ~}} diff --git a/ext/js/data/anki-note-data-creator.js b/ext/js/data/anki-note-data-creator.js index c7047633..fb9c8b8c 100644 --- a/ext/js/data/anki-note-data-creator.js +++ b/ext/js/data/anki-note-data-creator.js @@ -441,7 +441,7 @@ class AnkiNoteDataCreator { const results = []; const {headwords} = dictionaryEntry; for (let i = 0, ii = headwords.length; i < ii; ++i) { - const {term, reading, tags, sources: [{deinflectedText}]} = headwords[i]; + const {term, reading, tags, sources: [{deinflectedText}], wordClasses} = headwords[i]; const termTags = this.createCachedValue(this._convertTags.bind(this, tags)); const frequencies = this.createCachedValue(this._getTermExpressionFrequencies.bind(this, dictionaryEntry, i)); const pitches = this.createCachedValue(this._getTermExpressionPitches.bind(this, dictionaryEntry, i)); @@ -455,7 +455,8 @@ class AnkiNoteDataCreator { get frequencies() { return self.getCachedValue(frequencies); }, get pitches() { return self.getCachedValue(pitches); }, get furiganaSegments() { return self.getCachedValue(furiganaSegments); }, - get termFrequency() { return self.getCachedValue(termFrequency); } + get termFrequency() { return self.getCachedValue(termFrequency); }, + wordClasses }; results.push(item); } diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index 334445c6..fd62a558 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -459,7 +459,7 @@ class OptionsUtil { {async: false, update: this._updateVersion7.bind(this)}, {async: true, update: this._updateVersion8.bind(this)}, {async: false, update: this._updateVersion9.bind(this)}, - {async: false, update: this._updateVersion10.bind(this)} + {async: true, update: this._updateVersion10.bind(this)} ]; } @@ -750,9 +750,11 @@ class OptionsUtil { return options; } - _updateVersion10(options) { + async _updateVersion10(options) { // Version 10 changes: // Removed global option useSettingsV2. + // Added part-of-speech field template. + await this._applyAnkiFieldTemplatesPatch(options, '/data/templates/anki-field-templates-upgrade-v10.handlebars'); delete options.global.useSettingsV2; return options; } diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index 19e88b8a..724bec9c 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -250,10 +250,14 @@ class DisplayGenerator { node.dataset.readingIsSame = `${reading === expression}`; node.dataset.frequency = DictionaryDataUtil.getTermFrequency(termTags); - const pitchAccentCategories = this._getPitchAccentCategories(reading, pronunciations, headwordIndex); + const {wordClasses} = headword; + const pitchAccentCategories = this._getPitchAccentCategories(reading, pronunciations, wordClasses, headwordIndex); if (pitchAccentCategories !== null) { node.dataset.pitchAccentCategories = pitchAccentCategories; } + if (wordClasses.length > 0) { + node.dataset.wordClasses = wordClasses.join(' '); + } this._setTextContent(node.querySelector('.expression-reading'), reading); @@ -762,13 +766,14 @@ class DisplayGenerator { } } - _getPitchAccentCategories(reading, pronunciations, headwordIndex) { + _getPitchAccentCategories(reading, pronunciations, wordClasses, headwordIndex) { if (pronunciations.length === 0) { return null; } + const isVerbOrAdjective = this._isVerbOrAdjective(wordClasses); const categories = new Set(); for (const pronunciation of pronunciations) { if (pronunciation.headwordIndex !== headwordIndex) { continue; } for (const {position} of pronunciation.pitches) { - const category = this._japaneseUtil.getPitchCategory(reading, position, false); + const category = this._japaneseUtil.getPitchCategory(reading, position, isVerbOrAdjective); if (category !== null) { categories.add(category); } @@ -776,4 +781,19 @@ class DisplayGenerator { } return categories.size > 0 ? [...categories].join(' ') : null; } + + _isVerbOrAdjective(wordClasses) { + for (const wordClass of wordClasses) { + switch (wordClass) { + case 'v1': + case 'v5': + case 'vs': + case 'vk': + case 'vz': + case 'adj-i': + return true; + } + } + return false; + } } diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index ad9689ee..e99ac8db 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -917,8 +917,8 @@ class Translator { return {originalText, transformedText, deinflectedText, isPrimary}; } - _createTermHeadword(index, term, reading, sources, tags) { - return {index, term, reading, sources, tags}; + _createTermHeadword(index, term, reading, sources, tags, wordClasses) { + return {index, term, reading, sources, tags, wordClasses}; } _createTermDefinition(index, headwordIndices, dictionary, tags, entries) { @@ -953,7 +953,7 @@ class Translator { } _createTermDictionaryEntryFromDatabaseEntry(databaseEntry, originalText, transformedText, deinflectedText, reasons, isPrimary, enabledDictionaryMap) { - const {expression, reading: rawReading, definitionTags, termTags, glossary, score, dictionary, id, sequence} = databaseEntry; + const {expression, reading: rawReading, definitionTags, termTags, glossary, score, dictionary, id, sequence, rules} = databaseEntry; const reading = (rawReading.length > 0 ? rawReading : expression); const {index: dictionaryIndex, priority: dictionaryPriority} = this._getDictionaryOrder(dictionary, enabledDictionaryMap); const sourceTermExactMatchCount = (isPrimary && deinflectedText === expression ? 1 : 0); @@ -975,7 +975,7 @@ class Translator { dictionaryPriority, sourceTermExactMatchCount, maxTransformedTextLength, - [this._createTermHeadword(0, expression, reading, [source], headwordTagGroups)], + [this._createTermHeadword(0, expression, reading, [source], headwordTagGroups, rules)], [this._createTermDefinition(0, [0], dictionary, definitionTagGroups, glossary)] ); } @@ -1100,15 +1100,16 @@ class Translator { _addTermHeadwords(headwordsMap, headwords) { const headwordIndexMap = []; - for (const {term, reading, sources, tags} of headwords) { + for (const {term, reading, sources, tags, wordClasses} of headwords) { const key = this._createMapKey([term, reading]); let headword = headwordsMap.get(key); if (typeof headword === 'undefined') { - headword = this._createTermHeadword(headwordsMap.size, term, reading, [], []); + headword = this._createTermHeadword(headwordsMap.size, term, reading, [], [], []); headwordsMap.set(key, headword); } this._addUniqueSources(headword.sources, sources); this._addUniqueTagGroups(headword.tags, tags); + this._addUniqueStrings(headword.wordClasses, wordClasses); headwordIndexMap.push(headword.index); } return headwordIndexMap; diff --git a/ext/js/pages/settings/anki-controller.js b/ext/js/pages/settings/anki-controller.js index 37ae2cf7..4e56594a 100644 --- a/ext/js/pages/settings/anki-controller.js +++ b/ext/js/pages/settings/anki-controller.js @@ -99,6 +99,7 @@ class AnkiController { 'glossary', 'glossary-brief', 'glossary-no-dictionary', + 'part-of-speech', 'pitch-accents', 'pitch-accent-graphs', 'pitch-accent-positions', diff --git a/ext/settings.html b/ext/settings.html index a9c29a73..2f8c012c 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -2652,6 +2652,10 @@ <td>List of definitions for the term, except the dictionary tag is omitted.</td> </tr> <tr> + <td><code class="anki-field-marker">{part-of-speech}</code></td> + <td>Part of speech information for the term.</td> + </tr> + <tr> <td><code class="anki-field-marker">{pitch-accents}</code></td> <td>List of pitch accent downstep notations for the term.</td> </tr> |