From 008ffdb6bffc2855957be948a24c9e07730501d6 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 28 Nov 2020 14:30:50 -0500 Subject: [PATCH] Frequencies marker (#1074) * Update japanese.js tests * Simplify fallback/early exit * Add overloads to furigana and furiganaPlain handlebars helper functions * Expose unique expression/reading arrays (and subsequently counts) * Add {frequencies} marker --- README.md | 2 ++ docs/templates.md | 18 +++++++++-- ...anki-field-templates-upgrade-v6.handlebars | 17 ++++++++++ .../default-anki-field-templates.handlebars | 17 ++++++++++ ext/bg/js/anki-note-builder.js | 10 ++++++ ext/bg/js/settings/anki-controller.js | 1 + ext/bg/js/template-renderer.js | 31 +++++++++++++------ ext/mixed/js/japanese.js | 10 +++--- test/test-japanese.js | 19 ++++++++++++ 9 files changed, 108 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fd8e23a3..d487ad07 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Flashcard fields can be configured with the following steps: `{dictionary}` | Name of the dictionary from which the card is being created (unavailable in *grouped* mode). `{document-title}` | Title of the web page that the term appeared in. `{expression}` | Term expressed as kanji (will be displayed in kana if kanji is not available). + `{frequencies}` | Frequency information for the term. `{furigana}` | Term expressed as kanji with furigana displayed above it (e.g. 日本語にほんご). `{furigana-plain}` | Term expressed as kanji with furigana displayed next to it in brackets (e.g. 日本語[にほんご]). `{glossary}` | List of definitions for the term (output format depends on whether running in *grouped* mode). @@ -188,6 +189,7 @@ Flashcard fields can be configured with the following steps: `{cloze-suffix}` | Fragment of the containing `{sentence}` starting at the end of `{cloze-body}` until the end of `{sentence}`. `{dictionary}` | Name of the dictionary from which the card is being created. `{document-title}` | Title of the web page that the kanji appeared in. + `{frequencies}` | Frequency information for the kanji. `{glossary}` | List of definitions for the kanji. `{kunyomi}` | Kunyomi (Japanese reading) for the kanji expressed as katakana. `{onyomi}` | Onyomi (Chinese reading) for the kanji expressed as hiragana. diff --git a/docs/templates.md b/docs/templates.md index 1c9081d2..7425bc4a 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -44,21 +44,27 @@ This function can be helpful for debugging values when creating templates. ### `furigana` -Converts a definition to its furigana representation. +Converts a definition or expression/reading pair to its furigana representation.
Syntax: - {{#furigana}}<definition>{{/furigana}} + {{#furigana}}<definition>{{/furigana}}
+ {{#furigana expression reading}}{{/furigana}}
* _`definition`_
The definition to convert. + * _`expression`_
+ The expression to convert. + * _`reading`_
+ The reading to convert.
Example: ```handlebars {{#furigana}}{{.}}{{/furigana}} + {{#furigana "読む" "よむ"}}{{/furigana}} ``` Output: @@ -73,21 +79,27 @@ Converts a definition to its furigana representation. ### `furiganaPlain` -Converts a definition to its simplified furigana representation. +Converts a definition or expression/reading pair to its simplified furigana representation.
Syntax: {{#furiganaPlain}}<definition>{{/furigana}} + {{#furiganaPlain expression reading}}{{/furiganaPlain}}
* _`definition`_
The definition to convert. + * _`expression`_
+ The expression to convert. + * _`reading`_
+ The reading to convert.
Example: ```handlebars {{~#furiganaPlain~}}{{.}}{{~/furiganaPlain~}} + {{#furiganaPlain "読む" "よむ"}}{{/furiganaPlain}} ``` Output: diff --git a/ext/bg/data/anki-field-templates-upgrade-v6.handlebars b/ext/bg/data/anki-field-templates-upgrade-v6.handlebars index 33a2f949..809423ce 100644 --- a/ext/bg/data/anki-field-templates-upgrade-v6.handlebars +++ b/ext/bg/data/anki-field-templates-upgrade-v6.handlebars @@ -6,3 +6,20 @@ {{~/each~}} {{~/if~}} {{/inline}} + +{{#*inline "frequencies"}} + {{~#if (op ">" definition.frequencies.length 0)~}} +
    + {{~#each definition.frequencies~}} +
  • + {{~#if (op "!==" ../definition.type "kanji")~}} + {{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}( + {{~#furigana expression reading~}}{{~/furigana~}} + ) {{/if~}} + {{~/if~}} + {{~dictionary}}: {{frequency~}} +
  • + {{~/each~}} +
+ {{~/if~}} +{{/inline}} diff --git a/ext/bg/data/default-anki-field-templates.handlebars b/ext/bg/data/default-anki-field-templates.handlebars index 0b0e9ca6..1024e2e6 100644 --- a/ext/bg/data/default-anki-field-templates.handlebars +++ b/ext/bg/data/default-anki-field-templates.handlebars @@ -306,4 +306,21 @@ {{~/if~}} {{/inline}} +{{#*inline "frequencies"}} + {{~#if (op ">" definition.frequencies.length 0)~}} +
    + {{~#each definition.frequencies~}} +
  • + {{~#if (op "!==" ../definition.type "kanji")~}} + {{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}( + {{~#furigana expression reading~}}{{~/furigana~}} + ) {{/if~}} + {{~/if~}} + {{~dictionary}}: {{frequency~}} +
  • + {{~/each~}} +
+ {{~/if~}} +{{/inline}} + {{~> (lookup . "marker") ~}} diff --git a/ext/bg/js/anki-note-builder.js b/ext/bg/js/anki-note-builder.js index 33cd3a0b..b6114e4b 100644 --- a/ext/bg/js/anki-note-builder.js +++ b/ext/bg/js/anki-note-builder.js @@ -108,9 +108,19 @@ class AnkiNoteBuilder { _createNoteData(definition, mode, context, resultOutputMode, glossaryLayoutMode, compactTags) { const pitches = DictionaryDataUtil.getPitchAccentInfos(definition); const pitchCount = pitches.reduce((i, v) => i + v.pitches.length, 0); + const uniqueExpressions = new Set(); + const uniqueReadings = new Set(); + if (definition.type !== 'kanji') { + for (const {expression, reading} of definition.expressions) { + uniqueExpressions.add(expression); + uniqueReadings.add(reading); + } + } return { marker: null, definition, + uniqueExpressions: [...uniqueExpressions], + uniqueReadings: [...uniqueReadings], pitches, pitchCount, group: resultOutputMode === 'group', diff --git a/ext/bg/js/settings/anki-controller.js b/ext/bg/js/settings/anki-controller.js index d9b1591e..957f86d9 100644 --- a/ext/bg/js/settings/anki-controller.js +++ b/ext/bg/js/settings/anki-controller.js @@ -83,6 +83,7 @@ class AnkiController { 'dictionary', 'document-title', 'expression', + 'frequencies', 'furigana', 'furigana-plain', 'glossary', diff --git a/ext/bg/js/template-renderer.js b/ext/bg/js/template-renderer.js index 5dd33814..c1995acd 100644 --- a/ext/bg/js/template-renderer.js +++ b/ext/bg/js/template-renderer.js @@ -117,13 +117,13 @@ class TemplateRenderer { return this._escape(dump); } - _furigana(context, options) { - const definition = options.fn(context); - const segs = jp.distributeFurigana(definition.expression, definition.reading); + _furigana(context, ...args) { + const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args); + const segs = jp.distributeFurigana(expression, reading); let result = ''; for (const seg of segs) { - if (seg.furigana) { + if (seg.furigana.length > 0) { result += `${seg.text}${seg.furigana}`; } else { result += seg.text; @@ -133,20 +133,31 @@ class TemplateRenderer { return result; } - _furiganaPlain(context, options) { - const definition = options.fn(context); - const segs = jp.distributeFurigana(definition.expression, definition.reading); + _furiganaPlain(context, ...args) { + const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args); + const segs = jp.distributeFurigana(expression, reading); let result = ''; for (const seg of segs) { - if (seg.furigana) { - result += ` ${seg.text}[${seg.furigana}]`; + if (seg.furigana.length > 0) { + if (result.length > 0) { result += ' '; } + result += `${seg.text}[${seg.furigana}]`; } else { result += seg.text; } } - return result.trimLeft(); + return result; + } + + _getFuriganaExpressionAndReading(context, ...args) { + const options = args[args.length - 1]; + if (args.length >= 3) { + return {expression: args[0], reading: args[1]}; + } else { + const {expression, reading} = options.fn(context); + return {expression, reading}; + } } _kanjiLinks(context, options) { diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index ee0ac777..2177ceee 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -411,9 +411,9 @@ const jp = (() => { // Furigana distribution distributeFurigana(expression, reading) { - const fallback = [{furigana: reading, text: expression}]; - if (!reading) { - return fallback; + if (!reading || reading === expression) { + // Same + return [{furigana: '', text: expression}]; } let isAmbiguous = false; @@ -471,7 +471,9 @@ const jp = (() => { if (segments && !isAmbiguous) { return segments; } - return fallback; + + // Fallback + return [{furigana: reading, text: expression}]; } distributeFuriganaInflected(expression, reading, source) { diff --git a/test/test-japanese.js b/test/test-japanese.js index 54186a96..e70698da 100644 --- a/test/test-japanese.js +++ b/test/test-japanese.js @@ -334,6 +334,25 @@ function testDistributeFurigana() { [ {text: '長い間', furigana: 'ながいあいだ'} ] + ], + // Same/empty reading + [ + ['飼い犬', ''], + [ + {text: '飼い犬', furigana: ''} + ] + ], + [ + ['かいいぬ', 'かいいぬ'], + [ + {text: 'かいいぬ', furigana: ''} + ] + ], + [ + ['かいぬ', 'かいぬ'], + [ + {text: 'かいぬ', furigana: ''} + ] ] ];