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
This commit is contained in:
toasted-nutbread 2020-11-28 14:30:50 -05:00 committed by GitHub
parent 94d63f4f87
commit 008ffdb6bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 17 deletions

View File

@ -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). `{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. `{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). `{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. <ruby>日本語<rt>にほんご</rt></ruby>). `{furigana}` | Term expressed as kanji with furigana displayed above it (e.g. <ruby>日本語<rt>にほんご</rt></ruby>).
`{furigana-plain}` | Term expressed as kanji with furigana displayed next to it in brackets (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). `{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}`. `{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. `{dictionary}` | Name of the dictionary from which the card is being created.
`{document-title}` | Title of the web page that the kanji appeared in. `{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. `{glossary}` | List of definitions for the kanji.
`{kunyomi}` | Kunyomi (Japanese reading) for the kanji expressed as katakana. `{kunyomi}` | Kunyomi (Japanese reading) for the kanji expressed as katakana.
`{onyomi}` | Onyomi (Chinese reading) for the kanji expressed as hiragana. `{onyomi}` | Onyomi (Chinese reading) for the kanji expressed as hiragana.

View File

@ -44,21 +44,27 @@ This function can be helpful for debugging values when creating templates.
### `furigana` ### `furigana`
Converts a definition to its furigana representation. Converts a definition or expression/reading pair to its furigana representation.
<details> <details>
<summary>Syntax:</summary> <summary>Syntax:</summary>
<code>{{#furigana}}<i>&lt;definition&gt;</i>{{/furigana}}</code> <code>{{#furigana}}<i>&lt;definition&gt;</i>{{/furigana}}</code><br>
<code>{{#furigana <i>expression</i> <i>reading</i>}}{{/furigana}}</code><br>
* _`definition`_ <br> * _`definition`_ <br>
The definition to convert. The definition to convert.
* _`expression`_ <br>
The expression to convert.
* _`reading`_ <br>
The reading to convert.
</details> </details>
<details> <details>
<summary>Example:</summary> <summary>Example:</summary>
```handlebars ```handlebars
{{#furigana}}{{.}}{{/furigana}} {{#furigana}}{{.}}{{/furigana}}
{{#furigana "読む" "よむ"}}{{/furigana}}
``` ```
Output: Output:
@ -73,21 +79,27 @@ Converts a definition to its furigana representation.
### `furiganaPlain` ### `furiganaPlain`
Converts a definition to its simplified furigana representation. Converts a definition or expression/reading pair to its simplified furigana representation.
<details> <details>
<summary>Syntax:</summary> <summary>Syntax:</summary>
<code>{{#furiganaPlain}}<i>&lt;definition&gt;</i>{{/furigana}}</code> <code>{{#furiganaPlain}}<i>&lt;definition&gt;</i>{{/furigana}}</code>
<code>{{#furiganaPlain <i>expression</i> <i>reading</i>}}{{/furiganaPlain}}</code><br>
* _`definition`_ <br> * _`definition`_ <br>
The definition to convert. The definition to convert.
* _`expression`_ <br>
The expression to convert.
* _`reading`_ <br>
The reading to convert.
</details> </details>
<details> <details>
<summary>Example:</summary> <summary>Example:</summary>
```handlebars ```handlebars
{{~#furiganaPlain~}}{{.}}{{~/furiganaPlain~}} {{~#furiganaPlain~}}{{.}}{{~/furiganaPlain~}}
{{#furiganaPlain "読む" "よむ"}}{{/furiganaPlain}}
``` ```
Output: Output:

View File

@ -6,3 +6,20 @@
{{~/each~}} {{~/each~}}
{{~/if~}} {{~/if~}}
{{/inline}} {{/inline}}
{{#*inline "frequencies"}}
{{~#if (op ">" definition.frequencies.length 0)~}}
<ul style="text-align: left;">
{{~#each definition.frequencies~}}
<li>
{{~#if (op "!==" ../definition.type "kanji")~}}
{{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}(
{{~#furigana expression reading~}}{{~/furigana~}}
) {{/if~}}
{{~/if~}}
{{~dictionary}}: {{frequency~}}
</li>
{{~/each~}}
</ul>
{{~/if~}}
{{/inline}}

View File

@ -306,4 +306,21 @@
{{~/if~}} {{~/if~}}
{{/inline}} {{/inline}}
{{#*inline "frequencies"}}
{{~#if (op ">" definition.frequencies.length 0)~}}
<ul style="text-align: left;">
{{~#each definition.frequencies~}}
<li>
{{~#if (op "!==" ../definition.type "kanji")~}}
{{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}(
{{~#furigana expression reading~}}{{~/furigana~}}
) {{/if~}}
{{~/if~}}
{{~dictionary}}: {{frequency~}}
</li>
{{~/each~}}
</ul>
{{~/if~}}
{{/inline}}
{{~> (lookup . "marker") ~}} {{~> (lookup . "marker") ~}}

View File

@ -108,9 +108,19 @@ class AnkiNoteBuilder {
_createNoteData(definition, mode, context, resultOutputMode, glossaryLayoutMode, compactTags) { _createNoteData(definition, mode, context, resultOutputMode, glossaryLayoutMode, compactTags) {
const pitches = DictionaryDataUtil.getPitchAccentInfos(definition); const pitches = DictionaryDataUtil.getPitchAccentInfos(definition);
const pitchCount = pitches.reduce((i, v) => i + v.pitches.length, 0); 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 { return {
marker: null, marker: null,
definition, definition,
uniqueExpressions: [...uniqueExpressions],
uniqueReadings: [...uniqueReadings],
pitches, pitches,
pitchCount, pitchCount,
group: resultOutputMode === 'group', group: resultOutputMode === 'group',

View File

@ -83,6 +83,7 @@ class AnkiController {
'dictionary', 'dictionary',
'document-title', 'document-title',
'expression', 'expression',
'frequencies',
'furigana', 'furigana',
'furigana-plain', 'furigana-plain',
'glossary', 'glossary',

View File

@ -117,13 +117,13 @@ class TemplateRenderer {
return this._escape(dump); return this._escape(dump);
} }
_furigana(context, options) { _furigana(context, ...args) {
const definition = options.fn(context); const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args);
const segs = jp.distributeFurigana(definition.expression, definition.reading); const segs = jp.distributeFurigana(expression, reading);
let result = ''; let result = '';
for (const seg of segs) { for (const seg of segs) {
if (seg.furigana) { if (seg.furigana.length > 0) {
result += `<ruby>${seg.text}<rt>${seg.furigana}</rt></ruby>`; result += `<ruby>${seg.text}<rt>${seg.furigana}</rt></ruby>`;
} else { } else {
result += seg.text; result += seg.text;
@ -133,20 +133,31 @@ class TemplateRenderer {
return result; return result;
} }
_furiganaPlain(context, options) { _furiganaPlain(context, ...args) {
const definition = options.fn(context); const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args);
const segs = jp.distributeFurigana(definition.expression, definition.reading); const segs = jp.distributeFurigana(expression, reading);
let result = ''; let result = '';
for (const seg of segs) { for (const seg of segs) {
if (seg.furigana) { if (seg.furigana.length > 0) {
result += ` ${seg.text}[${seg.furigana}]`; if (result.length > 0) { result += ' '; }
result += `${seg.text}[${seg.furigana}]`;
} else { } else {
result += seg.text; 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) { _kanjiLinks(context, options) {

View File

@ -411,9 +411,9 @@ const jp = (() => {
// Furigana distribution // Furigana distribution
distributeFurigana(expression, reading) { distributeFurigana(expression, reading) {
const fallback = [{furigana: reading, text: expression}]; if (!reading || reading === expression) {
if (!reading) { // Same
return fallback; return [{furigana: '', text: expression}];
} }
let isAmbiguous = false; let isAmbiguous = false;
@ -471,7 +471,9 @@ const jp = (() => {
if (segments && !isAmbiguous) { if (segments && !isAmbiguous) {
return segments; return segments;
} }
return fallback;
// Fallback
return [{furigana: reading, text: expression}];
} }
distributeFuriganaInflected(expression, reading, source) { distributeFuriganaInflected(expression, reading, source) {

View File

@ -334,6 +334,25 @@ function testDistributeFurigana() {
[ [
{text: '長い間', furigana: 'ながいあいだ'} {text: '長い間', furigana: 'ながいあいだ'}
] ]
],
// Same/empty reading
[
['飼い犬', ''],
[
{text: '飼い犬', furigana: ''}
]
],
[
['かいいぬ', 'かいいぬ'],
[
{text: 'かいいぬ', furigana: ''}
]
],
[
['かいぬ', 'かいぬ'],
[
{text: 'かいぬ', furigana: ''}
]
] ]
]; ];