summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2021-03-26 19:50:54 -0400
committerGitHub <noreply@github.com>2021-03-26 19:50:54 -0400
commit90f7d5ba07340413aa7e43c3a0cc038690b32db3 (patch)
treeb3c57f9240de2e3a86cbc8dba5fe93d71e4067ae /ext
parent482dd8c8d8339d29c9e7a202cbf4c54bf7cf291d (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.handlebars30
-rw-r--r--ext/data/templates/default-anki-field-templates.handlebars31
-rw-r--r--ext/js/data/anki-note-data-creator.js5
-rw-r--r--ext/js/data/options-util.js6
-rw-r--r--ext/js/display/display-generator.js26
-rw-r--r--ext/js/language/translator.js13
-rw-r--r--ext/js/pages/settings/anki-controller.js1
-rw-r--r--ext/settings.html4
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>